Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/matlab/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 反应:在对象上循环以绑定useState函数不会更新应用程序的状态_Javascript_Reactjs_React Hooks - Fatal编程技术网

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,编辑我的答案以回应您的评论,基本上,您可以用两种方式中的任何一种来设置初始状态,无论哪种方式最适合您。此外,还将此状态行为的示例提取到自定义挂钩中。干杯。