Last active
June 4, 2021 22:33
-
-
Save trae410/2a8dbdb1ba38b60f3dc1503ab08fa146 to your computer and use it in GitHub Desktop.
Async get and set data in UseEffect while preventing memory leaks and eslint warnings
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useState, useEffect, useRef } from 'react' | |
// This component would be conditionally rendered inside a parent component so that we can test the memory leak | |
// eg: if condition === 'a' render UsersDocs else render SomeOtherPage | |
// I havent tested this code but the real scenario has multiple different types of usersDocs to get | |
// and multiple different isFetchingDocs states | |
// the goal is to fetch and set the data only once with no memory leak errors and no eslint exhaustive or missing deps warnings | |
const UsersDocs = () => { | |
const [docs, setDocs] = useState(null) // must be null initially | |
const [isFetchingDocs, setIsFetchingDocs] = useState(false) | |
const componentIsMountedRef = useRef(false) | |
// some async function | |
const getDocs = async () => { | |
return [{name: "doc1"}, {name: "doc2"}] | |
} | |
// get and the docs and set them into state if the component is mounted | |
const handleGetDocs = async (setIsFetchingDocs, setDocs) => { | |
try { | |
setIsFetchingDocs(true) | |
const resDocs = await getDocs() | |
if (componentIsMountedRef.current) { | |
setDocs(docs => { | |
// compare previous state to resDocs and only set if different | |
// could use something like: | |
// if (!docs || (resDocs && (docs.length !== resDocs.length))) { | |
// or | |
// if (JSON.stringify(docs) !== JSON.stringify(resDocs)) { | |
if (!docs) { | |
return resDocs | |
} else return docs | |
}) | |
setIsFetchingDocs(false) | |
} | |
} catch (err) { | |
console.log(err) | |
} | |
} | |
// track whether the component is mounted in a mutable variable | |
useEffect(() => { | |
componentIsMountedRef.current = true | |
return () => { | |
componentIsMountedRef.current = false | |
} | |
}, []) | |
// initiate getting and setting the docs | |
useEffect(() => { | |
if (!docs && !isFetchingDocs) { | |
handleGetDocs({setIsFetchingDocs, setDocs, getDocs}) | |
}, [ | |
//getDocs, // might be needed in the dependancy array if passed down in a prop or in context | |
setIsFetchingDocs, | |
setDocs | |
]) | |
return ( | |
<ul> | |
{ | |
isFetchingDocs ? <li>...loading</li> | |
: | |
docs.map(doc => { | |
return <li>{doc.name}</li> | |
} | |
} | |
</ul> | |
) | |
} | |
export default App |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment