从class组件迁移到function+hooks组件,在开发中需要注意的问题,从this指向转译到了闭包。
useEffect导致的闭包问题。
先来看以下代码。在class中实现
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}
componentDidMount() {
setInterval(() => {
this.setState({
count: this.state.count + 1,
});
}, 500);
}
render() {
return <div>class组件中的效果:{this.state.count}</div>;
}
}
同样的逻辑在使用hooks-useEffect实现
const ClosureQ = () => {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => {
setCount(count + 1);
}, 500);
return () => {
clearInterval(id);
};
}, []);
return <div>闭包问题下的count: {count}</div>;
};
闭包问题导致useEffect中缓存的函数中,储存了第一次加载时的count,导致每次执行interval时,都是count(0) + 1 -> 1
解决方案
使用useRef缓存count变量
export const ClosureARef = () => {
const [count, setCount] = useState(0);
const countSave = useRef(count);
useEffect(() => {
const id = setInterval(() => {
countSave.current += 1;
setCount(countSave.current);
}, 500);
return () => {
clearInterval(id);
};
});
return <div>用useRef解决闭包问题: {count}</div>;
};
用useEffect第二个参数,解决闭包问题(btw:这样会重复创建触发中的函数)
export const ClosureAParam = () => {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => {
setCount(count + 1);
}, 500);
return () => {
clearInterval(id);
};
}, [count]);
return (
<div>
用useEffect第二个参数,解决闭包问题(btw:这样会重复创建触发中的函数):
{count}
</div>
);
};
使用setCount方法传递函数,通过形参能获取到最新的count
export const ClosureACallback = () => {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => {
setCount((oldCount) => oldCount + 1);
}, 500);
return () => {
clearInterval(id);
};
}, []);
return <div>setCount方法传递函数,通过形参能获取到最新的count: {count}</div>;
};