猿问

setInterval 刷新应用而不是更新状态

我正在用 编写倒计时Expo。我正在使用functional components,所以我state是通过 React 的useState钩子处理的。


let [state, setState] = useState({

    secondsLeft: 25,

    started: false,

});

如果我按 aButton它确实会触发此功能:


let onPressHandler = (): void => {

    if(!state.started) {

        setState({...state, started: true});

        setInterval(()=> {

            setState({...state, secondsLeft: state.secondsLeft - 1});

            console.log(state.secondsLeft);

        }, 1000);

    }

}

问题是每 1000 毫秒 Expo 刷新应用程序而不是更新状态。

慕莱坞森
浏览 179回答 1
1回答

眼眸繁星

它更新状态,但它使用陈旧状态来执行此操作。一旦间隔开始,回调中的state变量将永远不会改变。setInterval相反,请使用状态更新函数的 setter 形式,因此您始终使用当时的状态:let onPressHandler = (): void => {&nbsp; &nbsp; if(!state.started) {&nbsp; &nbsp; &nbsp; &nbsp; setState({...state, started: true});&nbsp; &nbsp; &nbsp; &nbsp; setInterval(()=> {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setState(currentState => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const newState = {...currentState, secondsLeft: currentState.secondsLeft - 1};&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log(newState.secondsLeft);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return newState;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; }, 1000);&nbsp; &nbsp; }};没有以下内容会更简洁console.log:let onPressHandler = (): void => {&nbsp; &nbsp; if(!state.started) {&nbsp; &nbsp; &nbsp; &nbsp; setState({...state, started: true});&nbsp; &nbsp; &nbsp; &nbsp; setInterval(()=> {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setState(currentState => {...currentState, secondsLeft: currentState.secondsLeft - 1});&nbsp; &nbsp; &nbsp; &nbsp; }, 1000);&nbsp; &nbsp; }};单独说明:如果您有彼此独立更新的状态项,最佳实践是为它们使用单独的状态变量。此外,由于它们在您的函数中是常量,因此最好将它们声明为const. 像这样:const [secondsLeft, setSecondsLeft] = useState(25);const [started, setStarted] = useState(false);// ...let onPressHandler = (): void => {&nbsp; &nbsp; if(!started) {&nbsp; &nbsp; &nbsp; &nbsp; setStarted(true);&nbsp; &nbsp; &nbsp; &nbsp; setInterval(()=> {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setSecondsLeft(seconds => seconds - 1);&nbsp; &nbsp; &nbsp; &nbsp; }, 1000);&nbsp; &nbsp; }};此外,由于您不能完全依赖setInterval精确,我建议存储您的停止时间(“现在”加上 25 秒)并重新计算每次还剩多少秒:let onPressHandler = (): void => {&nbsp; &nbsp; const stopTime = Date.now() + (DURATION * 1000);&nbsp; &nbsp; setStarted(true);&nbsp; &nbsp; setSecondsLeft(DURATION);&nbsp; &nbsp; const timer = setInterval(()=> {&nbsp; &nbsp; &nbsp; &nbsp; const left = Math.round((stopTime - Date.now()) / 1000);&nbsp; &nbsp; &nbsp; &nbsp; if (left <= 0) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; clearInterval(timer);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setStarted(false);&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setSecondsLeft(left);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }, 1000);};现场示例(带有停止逻辑):const {useState} = React;const Example = () => {&nbsp; &nbsp; const DURATION = 25; // seconds&nbsp; &nbsp; const [started, setStarted] = useState(false);&nbsp; &nbsp; const [secondsLeft, setSecondsLeft] = useState(0);&nbsp; &nbsp; if (started) {&nbsp; &nbsp; &nbsp; &nbsp; return <div>Seconds left: {secondsLeft}</div>;&nbsp; &nbsp; }&nbsp; &nbsp; let onPressHandler = ()/*: void*/ => {&nbsp; &nbsp; &nbsp; &nbsp; const stopTime = Date.now() + (DURATION * 1000);&nbsp; &nbsp; &nbsp; &nbsp; setStarted(true);&nbsp; &nbsp; &nbsp; &nbsp; setSecondsLeft(DURATION);&nbsp; &nbsp; &nbsp; &nbsp; const timer = setInterval(()=> {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const left = Math.round((stopTime - Date.now()) / 1000);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (left <= 0) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; clearInterval(timer);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setStarted(false);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setSecondsLeft(left);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }, 1000);&nbsp; &nbsp; };&nbsp; &nbsp; return (&nbsp; &nbsp; &nbsp; &nbsp; <input&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type="button"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; onClick={onPressHandler}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value="Start"&nbsp; &nbsp; &nbsp; &nbsp; />&nbsp; &nbsp; );};ReactDOM.render(<Example />, document.getElementById("root"));<div id="root"></div><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.12.0/umd/react-dom.production.min.js"></script>
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答