Skip to content

Instantly share code, notes, and snippets.

@bennettdams
Last active September 25, 2019 15:53
Show Gist options
  • Save bennettdams/f6230618076a2a234eee20bd3edc222b to your computer and use it in GitHub Desktop.
Save bennettdams/f6230618076a2a234eee20bd3edc222b to your computer and use it in GitHub Desktop.
Custom hook to access a shared loading state in a component. The hook provides a wrapper for multiple composite function executions.
import * as React from "react";
import { useEffect, useState, useCallback } from "react";
import { render } from "react-dom";
import "./styles.css";
type UseSharedLoadingHook = () => {
isLoading: boolean;
compositeLoading: (callback: () => void) => Promise<void>;
increaseAmountRunningTasks: () => void;
decreaseAmountRunningTasks: () => void;
amountRunningTasks: number;
};
/**
* Custom hook to access a shared loading state in a component.
* The hook provides a wrapper for multiple composite function executions.
*/
export const useSharedLoading: UseSharedLoadingHook = () => {
// amount running tasks to gather composite loading executions from consumers of this hook
const [amountRunningTasks, setAmountRunningTasks] = useState<number>(0);
// shared isLoading state for all consuming components
const [isLoading, setIsLoading] = useState<boolean>(true);
useEffect(() => {
setIsLoading(amountRunningTasks !== 0);
}, [amountRunningTasks]);
const increaseAmountRunningTasks = () => {
setAmountRunningTasks(oldAmount => oldAmount + 1);
};
const decreaseAmountRunningTasks = () => {
setAmountRunningTasks(oldAmount => oldAmount - 1);
};
// wrapper function to increase/decrease the amount of running tasks, should be used by the consuming components
const compositeLoading = useCallback(async (callback: () => void) => {
increaseAmountRunningTasks();
try {
await callback();
} catch (e) {
console.log(e);
} finally {
decreaseAmountRunningTasks();
}
}, []);
return {
isLoading,
compositeLoading,
increaseAmountRunningTasks,
decreaseAmountRunningTasks,
amountRunningTasks
};
};
function App() {
const {
isLoading,
amountRunningTasks,
compositeLoading
} = useSharedLoading();
const handleSomeOperation = () => {
compositeLoading(async () => {
await new Promise(resolve => setTimeout(resolve, 1500));
});
};
const handleAnotherOperation = () => {
compositeLoading(async () => {
await new Promise(resolve => setTimeout(resolve, 1500));
});
};
return (
<div className="App">
<h1>useSharedLoading custom hook</h1>
<p>isLoading: {isLoading.toString()}</p>
{isLoading ? (
<h4 style={{ color: "orange" }}>I'm loading!</h4>
) : (
<h4 style={{ color: "green" }}>Not loading!</h4>
)}
<p>{amountRunningTasks}</p>
<button onClick={handleSomeOperation}>
Some operation that takes a while
</button>
<br />
<br />
<button onClick={handleAnotherOperation}>
Another operation that takes a while
</button>
</div>
);
}
const rootElement = document.getElementById("root");
render(<App />, rootElement);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment