React Query
+++ draft = true +++
Reference Global state Avoid prop drilling Access data accoss our application without copying flowchart A["PostsContext()"] B["posts state: [posts, setPosts]"] C["status state: [status, setStatus]"] D["PostsContext()"] E["refetch function hook"] A--create-->B C--refer-->B D--refer-->B Global components: Not remove dedup requests export function PostsContext({ children }) { // Every time call `PostsContext` function, we will create bellow objects const [posts, setPosts] = React.useState([]); const [error, setError] = React.useState(); const [status, setStatus] = React.useState("loading"); const refetch = async () => { try { setStatus("loading"); const posts = await axios.get("/api/posts").then((res) => res.data); setPosts(posts); setStatus("success"); } catch (err) { setstatus("error"); setError(err); } }; const contextValue = React.useMemo(() => ({ posts, status, error, refetch, })); return <context.Provider value={contextValue}>{children}</context.Provider>; } Consumer export default usePosts() { const {posts, status, error, refetch} = React.useContext(context); // Every component use `usePosts` then `refetch` will be called at mounting time // Not remove dedup requesting React.useEffect(() => { refetch() }, []); return { posts, status, error, refetch, } } Fix dedup requests export function PostsContext({ children }) { // Every time call `PostsContext` function, we will create bellow objects const [posts, setPosts] = React.useState([]); const [error, setError] = React.useState(); const [status, setStatus] = React.useState("loading"); // Add new ref object which cannot reset between re-rendering const activePromiseRef = React.useRef(false); // Stick `refetch` function with a new ref object // If any other requests that happen while the promise is still pending we will reuse the promise from the original request const refetch = () => { if (!activePromiseRef.current) { activePromiseRef.current = async () => { try { setStatus("loading"); const posts = await axios.get("/api/posts").then((res) => res.data); setPosts(posts); } catch (err) { setStatus("error"); setError(err); } finally { activePromiseRef.current = false; } }(); // Execute immediately } // If any other requests that happen while the promise is still pending we will reuse the promise from the original request (we don't fire extra one) return activePromiseRef.current; }; const contextValue = React.useMemo(() => ({ posts, status, error, refetch, })); return <context.Provider value={contextValue}>{children}</context.Provider>; }