简体   繁体   English

reactjs挂钩中的连续状态对象设置问题

[英]Issues with successive state object setting in reactjs hooks

I am starting to using react hooks and i decide to put an object instead of a variable in the useState function : 我开始使用react钩子,我决定在useState函数中放置一个对象而不是一个变量:

const [foo, setFoo] = useState({
    term: '',
    loading: false,
    ...
});

but later when I want to update it 但是后来我想更新它时

const onChange = (e) => { 

    const { value } = e.target;

    setFoo({ ...foo, term: value });

    if(value) setFoo({ ...foo, loading: true });

    ...

}

...

return (
   ...
   <input onChange={onChange} value={term} />
   ...
) 

1. Why in the second setFoo when I check the foo object I get alway term property equal to '' exactly like the initial value and the input don't get updated with the typed characters ? 1.为什么在第二个setFoo当我检查foo对象时,总是获得等于'' term属性,就像初始值一样,并且输入内容不会使用键入的字符进行更新?

- When I delete the second setFoo it works so I guess because setFoo is asynchronous but how to solve this issue ?. -当我删除第二个setFoo它可以工作,所以我想是因为setFoo是异步的,但如何解决此问题呢?

- I know that we can workaround this issue by managing to call setFoo just once but i want to know other solutions ? -我知道我们可以通过setFoo只调用一次setFoo来解决此问题,但是我想知道其他解决方案吗?

2. Why this kinda of issues never happened in redux ? 2.为什么这类问题在redux从未发生过?

The solution: use one setFoo like this: 解决方案:像这样使用一个setFoo

const onChange = (e) => { 

    const { value } = e.target;

    setFoo({ term: value, loading: !!value });

    ...

}

!! means "convert to boolean value". 表示“转换为布尔值”。

You can solve the issue by calling setFoo only once with all the new key-value pairs, like this: 您可以通过使用所有新的键值对仅调用一次setFoo来解决此问题,如下所示:

const onChange = (e) => { 

    const { value } = e.target;
    const loading = value ? true : false;
    setFoo({ ...state, term: value, loading });
    ....
}

Update: 更新:

For complex state update and more control on that part, you can use useReducer , and write a separate reducer to update the state. 对于复杂的状态更新和对该部分的更多控制,可以使用useReducer ,并编写一个单独的reducer来更新状态。

1. Probably because you have to destruct foo instead of state 1.可能是因为您必须破坏foo而不是state

setFoo({ ...foo, term: value });

working useState example 工作useState示例

2. Take a look at the additional hooks, especially useReducer 2.看一下额外的挂钩,尤其是useReducer

useReducer is usually preferable to useState when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one. 当您具有涉及多个子值的复杂状态逻辑时,或者当下一个状态取决于上一个状态时, useReducer通常比useState更可取。

And your code can become: 您的代码可以变成:

const reducer = (state, action) {
    switch(action.type) {
       case 'loading':
         return { ...state, loading: true };
       case 'loaded':
       default:
         return { ...state, loading: false };
    }
}

const initialState = {
  term: '',
  loading: false,
}
const [state, dispatch] = useReducer(reducer, initialState);
dispatch({
   type: e.target.value ? 'loaded' : 'loading'
});

working useReducer example on CodeSandbox useReducer上的work useReducer示例

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM