Javascript 反应:在对象上循环以绑定useState函数不会更新应用程序的状态
我正在尝试创建一个小库来清理这个模式Javascript 反应:在对象上循环以绑定useState函数不会更新应用程序的状态,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,我正在尝试创建一个小库来清理这个模式 const[a,setA]=useState(1) const[b,setB]=useState(2) 常数[c,setC]=useState(3) 常数[d,setD]=useState(4) 常数[e,setE]=useState(5) // ... 变成这样的东西 s({ 答:1,, b:2, c:3, d:4, e:5 },对) 我的想法是在提供给s()函数的对象上循环,并将每个键/值添加到状态保持对象中,如下所示: st={ 答:1,, set
const[a,setA]=useState(1)
const[b,setB]=useState(2)
常数[c,setC]=useState(3)
常数[d,setD]=useState(4)
常数[e,setE]=useState(5)
// ...
变成这样的东西
s({
答:1,,
b:2,
c:3,
d:4,
e:5
},对)
我的想法是在提供给s()
函数的对象上循环,并将每个键/值添加到状态保持对象中,如下所示:
st={
答:1,,
setA:useState()函数返回的数组中的第二项
//对b、c、d、e重复此模式。。。
}
它似乎在某种意义上工作,st.a
返回1
,st.setA
返回一个函数绑定的dispatchAction()
(我假设这就是useState()[1]
返回的内容)
但当您单击下面演示中的按钮时,它不会更新任何st
(在下面的示例中,我使用count
和cool
作为变量,而不是a、b、c、d、e
)
import React,{useState}来自“React”
从“react dom”导入react dom
//国家持有人。这可以被拉到全局状态的上下文中。
常数st={}
常量s=(对象,设置默认值=false)=>{
如果(设置默认值){
//在s({…},true)上循环以创建默认状态。
Object.keys(obj.map)(k=>{
st[k]=useState(obj[k])[0]
st[`set${k.charAt(0.toUpperCase()}${k.slice(1)}`]=useState(obj[k])[1]
返回空
})
}否则{
//使用st[setXyz(…)]更新状态
//修正:这不会更新状态。
//似乎是这样,因为它调用了setCount(2)之类的东西
//在'st'对象中使用绑定有函数的setCount。
for(让k在obj中){
st[`set${k.charAt(0.toUpperCase()}${k.slice(1)}`](obj[k])
}
控制台日志(st)
}
}
常量应用=()=>{
//设置默认状态对象。
//它比20行'const[x,setX]=useState(1)更漂亮`
(
{
计数:0,
酷:没错,
},
是的,
)
返回(
//在一个对象中更新所有状态。
({
计数:2,
酷:错,
})
}
>
点击
{/*通过st变量访问状态。*/}
const s = (obj, setDefaults = false) => {
if (setDefaults) {
// Loop over s({...}, true) to create default state.
Object.keys(obj).map(k => {
st[k] = useState(obj[k]);
return null;
});
} else {
// Update state using st[setXyz(...)]
// FIXME: This doesn't update the state.
// It seems like it would since it is calling things like setCount(2)
// using the setCount that has a function bound to it in the `st` object.
for (let k in obj) {
st[k][1](obj[k]);
console.log(st[k], obj[k]);
}
console.log(st);
}
};
{JSON.stringify(st,null,2)}
)
}
const rootElement=document.getElementById('root'))
render(试试这样的方法
//...
const App = () => {
const [state, setState] = useReducer(
(state, newState) => ({ ...state, ...newState }),
st
);
useEffect(() => {
setState({
count: 0,
cool: true
});
}, []);
//...
最终工作链接:您正在破坏:
仅在顶层调用挂钩
不要在循环、条件或嵌套函数中调用钩子。相反,请始终在React函数的顶层使用钩子
仅来自React函数的调用挂钩
不要从常规JavaScript函数调用钩子
对于使用较大大小状态的组件,我建议您使用useReducer
来处理它
例如,您可以使用useReducer
钩子拥有一个setState
函数,该函数可以将多个属性值一次合并到您的状态:
function useSetState(initialState) {
const [state, setState] = useReducer(
(state, newState) => ({...state, ...newState}),
initialState,
)
return [state, setState]
}
如您所见,您可以在组件装载时在useReducer
标记上设置初始状态(在上例中的useffect
调用中)
您还可以将此状态行为提取到自定义挂钩中,我发现它在重构基于类的组件时非常有用,因为它模拟了React.Component
setState
方法的行为:
因此,您可以像在基于类的组件中使用setState
一样简单地使用上述自定义挂钩
检查并检查以下物品:
另外,忘了提到“state holder”对象,我建议您只作为组件的“初始状态”,这就是为什么在我的示例中,我将它传递给useReducer
hook。因为我们让React处理状态,所以我们不应该直接改变这个对象,即“current”组件的状态将存在于我们在示例中呈现的state
标识符中。出于好奇,您似乎分配了值,但从未在st[k]
中更新它,为什么要将st
设置为初始状态
,但也使用useffect
(在组件安装时)要设置初始状态?@corysimmons,编辑我的答案以回应您的评论,基本上,您可以用两种方式中的任何一种来设置初始状态,无论哪种方式最适合您。此外,还将此状态行为的示例提取到自定义挂钩中。干杯。