I have a component where-in I need to fetch some data and render it. The component gets rendered initially. The problem I’m facing is when the handler function switchDocumentType
is called after clicking the button for a particular type, the whole component gets unmounted/un-rendered.
While debugging on my own I found this happens after setDocumentType
is run inside event handler function.
What is wrong in the below code snippet that could possibly cause this issue? I can see the useEffect
is not going in infinite-loop as well.
Code snippet:
import * as React from 'react'; const MyComponent = (props) => { const [documentType, setDocumentType] = React.useState('alpha'); const [documentData, setDocumentData] = React.useState(''); const types = ['alpha', 'beta', 'gamma']; React.useEffect(() => { myDataFetch('https://example.com/foo/?bar=123').then(async (response) => { const data = await response.json(); setDocumentData(data.terms); // html string const myDiv = document.getElementById('spacial-div'); myDiv.innerHTML = data; // need to render raw HTML inside a div }); }, [documentType]); const switchDocumentType = (type) => { setDocumentType(type); // send some analytics events }; const convertToPDF = () => { // uses documentData to generate PDF }; return ( <div className="container-div"> {types.map((type) => { return ( <button key={type} onClick={(type) => switchDocumentType(type)}> {type} </button> ); })} <div id="special-div" /> </div> ); }; export default MyComponent;
Advertisement
Answer
Not sure why but placing debuggers before state update causes this issue, not only for this component, but for all the other components I tried with. Seems to be an issue either with debugger or React. Removing debuggers solved the issue.
Also, now I’m returning a cleanup function inside useEffect
as pointed out in some stack-overflow posts. I also refactored the code as suggested by @iaq and @sheepiiHD to follow React best practices.
Updated code:
import * as React from 'react'; const MyComponent = (props) => { const [documentType, setDocumentType] = React.useState('alpha'); const [documentData, setDocumentData] = React.useState(''); const types = ['alpha', 'beta', 'gamma']; const fetchData = async () => { const response = await myDataFetch('https://example.com/foo/?bar=123') const data = await response.json(); setDocumentData(data); } React.useEffect(() => { fetchData(); return () => { setDocumentType(''); setDocumentData(''); }; }, []); const switchDocumentType = async (e, type) => { e.preventDefault(); setDocumentType(type); await fetchData(); // send some analytics events }; return ( <div className="container-div"> {types.map((type) => { return ( <button key={type} onClick={(e) => switchDocumentType(e, type)}> {type} </button> ); })} <div id="special-div" dangerouslySetInnerHTML={{__html: documentData.terms}} /> </div> ); }; export default MyComponent;