Effect 不依赖任何值
const Counter = () => {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => {
setCount(count + 1)
}, 1000)
return () => clearInterval(id);
}, [])
return (
<div>
{count}
</div>
)
}
Effect依赖某个值
const Counter = () => {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => {
setCount(count + 1)
}, 1000)
return () => clearInterval(id);
}, [count])
return (
<div>
{count}
</div>
)
}
Effect自给自足
使用类似 setState的函数形式
const Counter = () => {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => {
setCount(count => count +1)
}, 1000)
return () => clearInterval(id);
}, [step])
return (
<div>
{count}
</div>
)
}
相互依赖的状态
setCount(c => c + 1)并不完美,假设我们有两个相互依赖的状态,我们想基于某个props计算下一次的state,并不能做到。
const Counter = () => {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
useEffect(() => {
const id = setInterval(() => {
setCount(count => count + step)
}, 1000)
return () => clearInterval(id);
}, [step])
return (
<div>
{count}
<input value={step} onChange={e => setStep(Number(e.target.value))} />
</div>
)
}
使用useReducer
const initialState = {
count: 0,
step: 1,
};
function reducer(state, action) {
const { count, step } = state;
if (action.type === 'tick') {
return { count: count + step, step };
} else if (action.type === 'step') {
return { count, step: action.step };
} else {
throw new Error();
}
}
const Counter = () => {
const [state, dispatch] = useReducer(reducer, initialState);
const { count, step } = state;
useEffect(() => {
const id = setInterval(() => {
dispatch({type:'tick'});
}, 1000)
return () => clearInterval(id);
}, [dispatch])
return (
<div>
{count}
<input value={step} onChange={e => {
dispatch({
type: 'step',
step: Number(e.target.value)
});
}} />
</div>
)
}
当然你也可以把依赖的dispatch
去掉,useReducer是hooks中的作弊模式
,它可以把相互依赖的逻辑分开,避免不必要的effect调用。