SOU*_*PTA 1 javascript settimeout reactjs react-hooks use-effect
通过不深入实际用法,我创建了一个简单的示例来解释我想要做什么。
我有一个状态对象{num:0},我想在 10 秒内每秒更新一次 num,据此,我创建了一个工作完美的类组件。
class App extends React.Component {
constructor() {
super();
this.state = {
num: 0
};
}
componentDidMount = () => {
for (let i = 0; i < 10; i++) {
setTimeout(() => this.setState({ num: this.state.num + 1 }), i * 1000);
}
};
render() {
return (
<>
<p>hello</p>
<p>{this.state.num}</p>
</>
);
}
}
Run Code Online (Sandbox Code Playgroud)
现在我想在功能组件中复制相同的功能,但我做不到。我尝试如下图所示:
const App = () => {
const [state, setState] = React.useState({ num: 0 });
React.useEffect(() => {
for (let i = 0; i < 10; i++) {
setTimeout(() => setState({ num: state.num + 1 }), i * 1000);
}
}, []);
return (
<>
<p>hello</p>
<p>{state.num}</p>
</>
);
};
Run Code Online (Sandbox Code Playgroud)
谁能帮我解决我在这里做错的事情吗?
所有超时都会运行,但因为您在第一次渲染时将它们全部设置,所以您在初始值周围创建了一个闭包state.num,因此当每个超时触发时,它都会将新的状态值设置为0 + 1,并且不会发生任何变化。
评论中提到的重复内容涵盖了详细信息,但这里有一个快速工作片段,使用 aref作为计数器,在 10 次迭代后停止,并在 useEffect 返回时清理计时器。
const App = () => {
const [state, setState] = React.useState({ num: 0 });
const counter = React.useRef(0);
React.useEffect(() => {
if (counter.current < 10) {
counter.current += 1;
const timer = setTimeout(() => setState({ num: state.num + 1 }), 1000);
return () => clearTimeout(timer);
}
}, [state]);
return (
<div>
<p>hello</p>
<p>{state.num}</p>
</div>
);
};
ReactDOM.render(
<App />,
document.getElementById("root")
);Run Code Online (Sandbox Code Playgroud)
<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>Run Code Online (Sandbox Code Playgroud)
为了让你的代码按原样工作,一次性设置所有这些,你可以将回调传递给调用setState()以避免创建闭包,但是你放弃了通过在每个渲染上设置新的超时来允许的粒度控制。
const App = () => {
const [state, setState] = React.useState({ num: 0 });
React.useEffect(() => {
for (let i = 0; i < 10; i++) {
setTimeout(() => setState(prevState => ({ ...prevState, num: prevState.num + 1 })), i * 1000);
}
}, []);
return (
<div>
<p>hello</p>
<p>{state.num}</p>
</div>
);
};
ReactDOM.render(
<App />,
document.getElementById("root")
);Run Code Online (Sandbox Code Playgroud)
<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>Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10112 次 |
| 最近记录: |