Search code examples
javascriptreactjsreact-nativethrottling

throttle function does not work when i update state inside this function


below is code. runonce function does nt work as (it should run only once in 3000ms) but if i does not update state then it works fine.

const HomeScreen = ({ navigation }) => {
    const [count, setCount] = useState(1)

    function runOnce(func, delay) {
        let timer = null;
        return function (...args) {
            if (!timer) {
                timer = setTimeout(() => {
                    timer = null;
                }, delay);
                return func(...args);
            }
        };
    }

    const handleButtonClick = runOnce(() => {
        console.log("This function will run only once in 3000 milliseconds");
        //here if i don't update below state then console runs only once in 3000ms 
        // but if i update state then it runs whenever i click button 
        setCount(prev => prev + 1)
    }, 3000);



    return <SafeAreaView style={{ flex: 1 }}>
        <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
            <Text style={{ margin: 10, color: 'red', fontSize: 24 }}>{count}</Text>
            <TouchableOpacity style={{ marginTop: 10 }} onPress={() => handleButtonClick()}>
                <Text style={{ color: 'blue' }}>Increment Count</Text>
            </TouchableOpacity>
        </View>
    </SafeAreaView>
}

as expected the function inside runonce should run only once in every 3000ms no mattar how many times you click


Solution

  • When updating state, your function reruns and reconstructs your click handler to be a new function on every render, each time with a new timer.

    To avoid this, memoize the function using useCallback.

    const handleButtonClick = useCallback(() => runOnce(() => {
            console.log("This function will run only once in 3000 milliseconds");
            //here if i don't update below state then console runs only once in 3000ms 
            // but if i update state then it runs whenever i click button 
            setCount(prev => prev + 1)
        }, 3000), []);