Skip to content

Instantly share code, notes, and snippets.

@codemzy
Created February 25, 2021 11:03
Show Gist options
  • Save codemzy/6551e64d50704e2a4b322cdd4412b625 to your computer and use it in GitHub Desktop.
Save codemzy/6551e64d50704e2a4b322cdd4412b625 to your computer and use it in GitHub Desktop.
React useDelay hook - to avoid flash of loading content
import React from "react";
// delay a state change (used for loading or waiting for async to avoid flash of loading state)
export default function useDelay(initial, { delay = 300, delayedValue = true, minDuration = 700 }) {
const [state, setState] = React.useState(initial);
const [change, setChange] = React.useState(initial);
const end = React.useRef(0);
React.useEffect(() => {
let timer;
let timeLeft = end.current - Date.now();
if (change === delayedValue) {
// create a timer to only set the state if unchanged after the delay time
timer = setTimeout(function() {
setState(change);
end.current = Date.now() + minDuration; // record time that state can change again due to minDuration
}, delay);
} else if (timeLeft > 0) {
// create a timer to only change the state after the minDuration
timer = setTimeout(function() {
setState(change);
}, timeLeft);
} else {
setState(change);
}
// clean up
return function() {
timer && clearTimeout(timer); // clear any timeout
}
}, [change]);
return [state, setChange];
};
@codemzy
Copy link
Author

codemzy commented Feb 25, 2021

For use with loading state

import useDelay from '../../hooks/useDelay';

function MyComponent(props) {
    // state
    const [loading, setLoading] = useDelay(false, { delayedValue: true, delay: 200, minDuration: 1000 });
    ...

    // some async action
    function doAsync() {
        setLoading(true); // this will be delayed due to the useDelay hook so faster connections won't get loading flash
        apiRequest().then(function(response) {
            ...set some other state with response
        });
    };

  ...
};

For use with single status state

import useDelay from '../../hooks/useDelay';

function MyComponent(props) {
    // state
    const [status, setStatus] = useDelay(false, { delayedValue: "loading", delay: 200, minDuration: 1000 });
    ...

    // some async action
    function doAsync() {
        setStatus("loading"); // this will be delayed due to the useDelay hook so faster connections won't get loading flash
        apiRequest().then(function(response) {
            setStatus("resolved"); // this will be set immediately
        });
    };

  ...
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment