A simple state management library for smooth react page loading experience.
yarn add use-loading-steps
# or
npm install --save use-loading-steps
const [loadingState, setStepDone, resetLoading, skipStep] = useLoadingSteps(taskCount, initLoaded, options);
useLoadingSteps hook params
taskCount
: the number of steps should be done before the page is loaded.initLoaded
: set to true to skip all state transitions, loadingState =DONE
.options
: see below.
Hook returns
loadingState
: the state, type:LState
enum (string).setStepDone('step_name')
: to be called when a step is finished, step_name should be a unique string.resetLoading()
: to be called when reloading resources.skipStep('step_name)
: same effect as setStepDone, but prints different debug log.
Options
interface Options {
renderDelay?: number; // timeout of SILENT_LOADING state after started
resetDelay?: number; // timeout of SILENT_LOADING state after reset
doneDelay?: number; // timeout of DELAY_DONE state
name?: string; // for debug log (useful if there are multiple pages / components use this hook)
}
The debug log is printed by console.debug
, and is skipped in production build.
export enum LState {
SILENT_LOADING = 'SILENT_LOADING', // for: do loading but not to show loading animation
LOADING = 'LOADING', // for: show loading animation
DELAY_DONE = 'DELAY_DONE', // for: loading finished but keep showing loading animation
DONE = 'DONE', // for: all ready
}
Utility functions
export const isLoading = (state: LState) => LState.LOADING === state;
export const isReloading = (state: LState) => [LState.SILENT_LOADING, LState.LOADING].includes(state);
export const isDone = (state: LState) => LState.DONE === state;
// Number of steps: 2, loaded: false, renderDelay: 100ms
const [loadingState, setStepDone] = useLoadingSteps(2, false, {renderDelay: 100});
const [rows, setRows] = useState([]);
useEffect(async () => {
const data = await fetchData();
setStepDone('fetch');
const rows = await transformData(data);
setStepDone('transform');
}, []);
if (isLoading(loadingState)) {
return <div>(Loading animation)</div>;
}
return (
<div>
{data.map((item) => <div>row: {item}</div>)}
</div>
);
Explanation
- Initialize, if loaded = false, state =>
SILENT_LOADING
, isLoading(loadingState) = false - After 100ms, if not finished, state =>
LOADING
, isLoading(loadingState) = true - After the two
setStepDone('step name')
are called, state =>DONE
, isLoading(loadingState) = false
More examples
- Please refer to unit tests in
lib/__test__
.