我正在尝试通过反应做倒数计时器。从10到0基本上是倒数计时,当0时我将调用某个函数。
我理想地找到了一些例子:https://codesandbox.io/s/0q453m77nw?from-embed 但这是一个类组件,我不想使用功能组件和挂钩来做到这一点,但是我做不到。
我尝试过:
function App() {
const [seconds, setSeconds] = useState(10);
useEffect(() => {
setSeconds(setInterval(seconds, 1000));
}, []);
useEffect(() => {
tick();
});
function tick() {
if (seconds > 0) {
setSeconds(seconds - 1)
} else {
clearInterval(seconds);
}
}
return (
<div className="App">
<div
{seconds}
</div>
</div>
);
}
export default App;
它很快就会从10倒数到0,而不是10秒。 我在哪里弄错了?
答案 0 :(得分:2)
似乎有多个useEffect
挂钩导致倒计时每秒运行一次以上。
这是一个简化的解决方案,我们在seconds
钩中检查useEffect
并选择以下一项:
setTimeout
更新seconds
,或者
function App() {
const [seconds, setSeconds] = React.useState(10);
React.useEffect(() => {
if (seconds > 0) {
setTimeout(() => setSeconds(seconds - 1), 1000);
} else {
setSeconds('BOOOOM!');
}
});
return (
<div className="App">
<div>
{seconds}
</div>
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
答案 1 :(得分:1)
您在乎精度吗?如果是这样,则不需要setInterval。如果您不关心精度(也可能不关心),则可以按一定的时间间隔安排对tick()
的呼叫,而不是相反。
const TimeoutComponent extends Component {
constructor(props) {
super(props);
this.state = { countdown: 10 };
this.timer = setInterval(() => this.tick(), props.timeout || 10000);
}
tick() {
const current = this.state.countdown;
if (current === 0) {
this.transition();
} else {
this.setState({ countdown: current - 1 });
}
}
transition() {
clearInterval(this.timer);
// do something else here, presumably.
}
render() {
return <div className="timer">{this.state.countDown}</div>;
}
}
答案 2 :(得分:0)
这取决于您的逻辑。在当前情况下,您运行useEffect
方法的tick
在每个渲染器上运行。您可以在下面找到一个简单的示例。
function App() {
const [seconds, setSeconds] = useState(10);
const [done, setDone] = useState(false);
const foo = useRef();
useEffect(() => {
function tick() {
setSeconds(prevSeconds => prevSeconds - 1)
}
foo.current = setInterval(() => tick(), 1000)
}, []);
useEffect(() => {
if (seconds === 0) {
clearInterval(foo.current);
setDone(true);
}
}, [seconds])
return (
<div className="App">
{seconds}
{done && <p>Count down is done.</p>}
</div>
);
}
首先要进行倒数计时。由于interval会使用回调一来设置状态,因此会创建一个闭包。在第二个效果中,我们正在检查条件。