• useState无论调用多少次,相互之间是独立的。react是根据useState出现的顺序来保证多个useState之间是相互独立 ```javascript let showFruit = true; function ExampleWithManyStates() { const [age, setAge] = useState(42);

      if(showFruit) { const [fruit, setFruit] = useState(‘banana’); showFruit = false; } const [todos, setTodos] = useState([{ text: ‘Learn Hooks’ }]); }

    //第一次渲染 useState(42); //将age初始化为42 useState(‘banana’); //将fruit初始化为banana useState([{ text: ‘Learn Hooks’ }]); //将todos初始化为[{ text: ‘Learn Hooks’ }]

    //第二次渲染 useState(42); //读取状态变量age的值(这时候传的参数42直接被忽略) // useState(‘banana’);
    useState([{ text: ‘Learn Hooks’ }]); //读取到的却是状态变量fruit的值,导致报错

    1. - 解决useState多次渲染的问题
    2. ```javascript
    3. // 以下代码执行完会导致页面渲染两遍
    4. const [loading, setLoading] = useState(true);
    5. const [data, setData] = useState(null);
    6. useEffect(async () => {
    7. const res = await axios.get("xxx");
    8. setLoading(false);
    9. setData(res);
    10. }, []);
    11. // 原因是,在React中,同步代码会合并渲染,异步代码不会合并渲染。
    12. // 以下代码只会渲染一次,它会将setLoading和setData进行合并。这个其实和类组件是一样的,在异步函数中不会合并setState。
    13. const [loading, setLoading] = useState(true);
    14. const [data, setData] = useState(null);
    15. useEffect(() => {
    16. setLoading(false);
    17. setData({ a: 1 });
    18. }, []);
    19. // 解决方案一:多个状态合并到一个状态中
    20. const [request, setRequest] = useState({ loading: true, data: null });
    21. useEffect(async () => {
    22. const res = await axios.get("xxx");
    23. setRequest({ loading: false, data: res });
    24. }, []);
    25. // 缺点:如果只想setState一个依赖项时,需要将别的依赖项也要传进去,否则这个值会丢失。React内部并不会帮你做去合并
    26. setRequest({ data: res }); // 就会导致loading值丢失了。
    27. // 解决方案是使用setRequest({ ...request, data: res }) 或者 setRequest((prevState) => ({ ...prevState, data: res }));
    28. // 解决方案二:写一个自定义合并依赖项的hook
    29. const useMergeState = (initialState) => {
    30. const [state, setState] = useState(initialState);
    31. const setMergeState = (newState) =>
    32. setState((prevState) => ({ ...prevState, newState }));
    33. return [state, setMergeState];
    34. };
    35. const [request, setRequest] = useMegeState({ loading: false, data: null });
    36. useEffect(async () => {
    37. const res = await axios.get("xxx");
    38. setRequest({ loading: true, data: res });
    39. // setRequest({ data: { a: 1 } }); // loading 状态不会丢失,还是 true
    40. }, []);
    41. // 解决方案三:使用useReducer
    42. const initState = { loading: false, data: null }
    43. function loginReducer(state, action) {
    44. if(action.type==='login'){
    45. return {...state,...action.newState}
    46. }
    47. }
    48. const [state, dispatch] = useReducer(loginReducer,initState);
    49. useEffect(async () => {
    50. const res = await axios.get("xxx");
    51. dispatch({ type: 'login', newState: {loading: true, data: res} });
    52. // setRequest({ data: { a: 1 } }); // loading 状态不会丢失,还是 true
    53. }, []);