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的值,导致报错
- 解决useState多次渲染的问题
```javascript
// 以下代码执行完会导致页面渲染两遍
const [loading, setLoading] = useState(true);
const [data, setData] = useState(null);
useEffect(async () => {
const res = await axios.get("xxx");
setLoading(false);
setData(res);
}, []);
// 原因是,在React中,同步代码会合并渲染,异步代码不会合并渲染。
// 以下代码只会渲染一次,它会将setLoading和setData进行合并。这个其实和类组件是一样的,在异步函数中不会合并setState。
const [loading, setLoading] = useState(true);
const [data, setData] = useState(null);
useEffect(() => {
setLoading(false);
setData({ a: 1 });
}, []);
// 解决方案一:多个状态合并到一个状态中
const [request, setRequest] = useState({ loading: true, data: null });
useEffect(async () => {
const res = await axios.get("xxx");
setRequest({ loading: false, data: res });
}, []);
// 缺点:如果只想setState一个依赖项时,需要将别的依赖项也要传进去,否则这个值会丢失。React内部并不会帮你做去合并
setRequest({ data: res }); // 就会导致loading值丢失了。
// 解决方案是使用setRequest({ ...request, data: res }) 或者 setRequest((prevState) => ({ ...prevState, data: res }));
// 解决方案二:写一个自定义合并依赖项的hook
const useMergeState = (initialState) => {
const [state, setState] = useState(initialState);
const setMergeState = (newState) =>
setState((prevState) => ({ ...prevState, newState }));
return [state, setMergeState];
};
const [request, setRequest] = useMegeState({ loading: false, data: null });
useEffect(async () => {
const res = await axios.get("xxx");
setRequest({ loading: true, data: res });
// setRequest({ data: { a: 1 } }); // loading 状态不会丢失,还是 true
}, []);
// 解决方案三:使用useReducer
const initState = { loading: false, data: null }
function loginReducer(state, action) {
if(action.type==='login'){
return {...state,...action.newState}
}
}
const [state, dispatch] = useReducer(loginReducer,initState);
useEffect(async () => {
const res = await axios.get("xxx");
dispatch({ type: 'login', newState: {loading: true, data: res} });
// setRequest({ data: { a: 1 } }); // loading 状态不会丢失,还是 true
}, []);