Last active
June 4, 2021 22:33
Revisions
-
trae410 revised this gist
Jun 4, 2021 . No changes.There are no files selected for viewing
-
trae410 revised this gist
Jun 4, 2021 . No changes.There are no files selected for viewing
-
trae410 revised this gist
Jun 4, 2021 . No changes.There are no files selected for viewing
-
trae410 revised this gist
Jun 4, 2021 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -8,7 +8,7 @@ import React, { useState, useEffect, useRef } from 'react' // 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) -
trae410 created this gist
Jun 4, 2021 .There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,79 @@ 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