我有三个问题:
我可以接着使用多个useState而没有副作用吗?我知道可以将这两个值放在一个对象中,但是如果我不想这样做,是否有可能没有副作用?像它会重新触发两个渲染吗?:
useEffect(
() => {
setCount(count);
setText(`Clicked ${count}`);
},
[count],
);
与上述相同的问题,但是将useState与useReducer交换:
useEffect(
() => {
setCount({ type: 'onClick', count });
setText({ type: 'onChangeText', text: `Clicked ${count}` });
},
[count],
);
同样是一个问题,但每个问题中只有一个:
useEffect(
() => {
setCount(count);
setText({ type: 'onChangeText', text: `Clicked ${count}` });
},
[count],
);
答案 0 :(得分:0)
您的所有示例仅呈现一次,因为您没有在异步函数后设置状态或调度。。如果要在异步函数之后执行设置状态或调度,则组件将在会导致状态更改的每个设置状态或调度上呈现。
尽管您的示例有点差劲,因为当count更改为count的值时,为什么要在效果中设置count?就像这样做:setCount(count=>count)
,并且不进行任何设置也不会导致重新渲染。
您可以使用ReactDOM.unstable_batchedUpdates
批量更新多个状态或调度多个动作,但是如果这些值相关,那么也许您应该将它们组合为状态或创建一个可同时更新两个值的reducer。
这里是一个演示,展示了在设置状态或在异步函数后多次调度时的多个渲染。使用stable_batchedUpdates时,没有多个渲染。
const reducer = (state, action) => state + 1;
const useABC = () => {
const [a, setA] = React.useState(0);
const [b, setB] = React.useState(0);
const [c, setC] = React.useState(0);
const [state, dispatch] = React.useReducer(reducer, 0);
const ref = React.useRef([]);
const reducerRef = React.useRef([]);
ref.current = ref.current.concat(
`render:${ref.current.length + 1} a:${a} b:${b} c:${c}`
);
reducerRef.current = reducerRef.current.concat(
`render:${
reducerRef.current.length + 1
} state:${state}, c:${c}`
);
const up = React.useCallback(
() => setC((c) => c + 1),
[]
);
return [
[setA, setB, up, c, ref],
[state, dispatch, reducerRef],
];
};
const Output = React.memo(function Output({ up, c, r }) {
return (
<div>
<button onClick={up}>{c}</button>
<pre>{JSON.stringify(r, undefined, 2)}</pre>
</div>
);
});
//when c increases it causes one render
// then when a is set to c it causes a render
// then when b is set to c it causes a render
const SetState = () => {
const [[setA, setB, up, c, ref]] = useABC();
React.useEffect(() => {
Promise.resolve().then(() => {
setA(c);
setB(c);
});
}, [c, setA, setB]);
return <Output c={c} up={up} r={ref.current} />;
};
//when c increases it causes one render
// then when state is increased it causes a render
// then when state is increased again it causes a render
const Reducer = () => {
const [[, , up, c], [, dispatch, ref]] = useABC();
React.useEffect(() => {
if (c !== 0) {
Promise.resolve().then(() => {
dispatch();
dispatch();
});
}
}, [c, dispatch]);
return <Output c={c} up={up} r={ref.current} />;
};
const BatchUpdated = () => {
const [[setA, setB, up, c, ref]] = useABC();
React.useEffect(() => {
Promise.resolve().then(() => {
//using batch updated
ReactDOM.unstable_batchedUpdates(() => {
setA(c);
setB(c);
});
});
}, [c, setA, setB]);
return <Output c={c} up={up} r={ref.current} />;
};
const App = () => {
return (
<div>
<h1>batch updates</h1>
<BatchUpdated />
<h1>set state</h1>
<SetState />
<h1>reducer</h1>
<Reducer />
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
答案 1 :(得分:0)
希望您知道在依赖它的效果中更新状态时发生了什么
这是代码沙箱,请思考为什么它显示i=11
https://codesandbox.io/s/optimistic-ride-4rvci?file=/src/App.js
如果您了解我的观点,则可以自由使用它,并进行无限循环去皮
这不是一个好习惯,如果您不需要循环,只需更新其他状态或在jsx中使用count
或count
中的tmp vars即可;如果需要循环,为什么不显式循环并在计算后更新最终状态