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

时间:2020-03-21 17:18:21

标签: javascript typescript react-native expo setinterval

我正在用public class Test { private int foo(){ System.out.println("Test"); return 1; } public static void main(String [] args) throws InterruptedException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Test innerClassObject = new Test(); Method method = innerClassObject.getClass().getDeclaredMethod("foo",null); method.setAccessible(true); method.invoke(innerClassObject); } } 编码倒计时。 我正在使用Expo,所以我的functional components是通过React的state钩子处理的。

useState

如果我按下let [state, setState] = useState({ secondsLeft: 25, started: false, }); ,则会触发此功能:

Button

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

enter image description here

可以帮我吗?

1 个答案:

答案 0 :(得分:0)

它更新状态,但是它使用陈旧状态来更新。一旦间隔开始,state回调中的setInterval变量就永远不会改变。

相反,请使用状态更新功能的设置器形式,因此您始终使用当时的状态:

let onPressHandler = (): void => {
    if(!state.started) {
        setState({...state, started: true});
        setInterval(()=> {
            setState(currentState => {
                const newState = {...currentState, secondsLeft: currentState.secondsLeft - 1};
                console.log(newState.secondsLeft);
                return newState;
            });
        }, 1000);
    }
};

如果没有console.log,则更加简洁:

let onPressHandler = (): void => {
    if(!state.started) {
        setState({...state, started: true});
        setInterval(()=> {
            setState(currentState => {...currentState, secondsLeft: currentState.secondsLeft - 1});
        }, 1000);
    }
};

另外,请注意:如果状态项彼此独立更新,则最佳实践是为它们使用单​​独的状态变量。另外,由于它们在您的函数中是恒定的,因此最好将它们声明为const。像这样:

const [secondsLeft, setSecondsLeft] = useState(25);
const [started, setStarted] = useState(false);

// ...
let onPressHandler = (): void => {
    if(!started) {
        setStarted(true);
        setInterval(()=> {
            setSecondsLeft(seconds => seconds - 1);
        }, 1000);
    }
};

此外,由于您不能完全依靠setInterval,因此建议存储您的停止时间(“现在”加上25秒)并重新计算每次还剩下多少秒:

let onPressHandler = (): void => {
    const stopTime = Date.now() + (DURATION * 1000);
    setStarted(true);
    setSecondsLeft(DURATION);
    const timer = setInterval(()=> {
        const left = Math.round((stopTime - Date.now()) / 1000);
        if (left <= 0) {
            clearInterval(timer);
            setStarted(false);
        } else {
            setSecondsLeft(left);
        }
    }, 1000);
};

实时示例(具有停止逻辑)

const {useState} = React;

const Example = () => {
    const DURATION = 25; // seconds
    const [started, setStarted] = useState(false);
    const [secondsLeft, setSecondsLeft] = useState(0);

    if (started) {
        return <div>Seconds left: {secondsLeft}</div>;
    }

    let onPressHandler = ()/*: void*/ => {
        const stopTime = Date.now() + (DURATION * 1000);
        setStarted(true);
        setSecondsLeft(DURATION);
        const timer = setInterval(()=> {
            const left = Math.round((stopTime - Date.now()) / 1000);
            if (left <= 0) {
                clearInterval(timer);
                setStarted(false);
            } else {
                setSecondsLeft(left);
            }
        }, 1000);
    };
    return (
        <input
            type="button"
            onClick={onPressHandler}
            value="Start"
        />
    );
};

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>