Can't perform a React state update on an unmounted component.(UseEffect)(Context API)(REACT.js)

618 views Asked by At

So I am getting this Warning:-

*Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
    in Products (created by Context.Consumer)*

Well, it's occurring in the Products Component When I Reroute to Product Edit component! Products component is used to list all products and product edit is used to edit product details and both these components are connected to the same context API using useContext. My Context API provider looks like this

*import React, { useState , createContext , useEffect} from 'react';
import firebase from "../firebase";

export const ProdContext = createContext();

const ProdContextProvider = props => {
    const [products , setproducts]= useState([])
    const [loading , setloading] = useState(true)
    const [subcribe , setsubcribe] = useState(false)


    const unsub =()=>{
        setsubcribe(false);
        console.log("unsubcribe--"+subcribe)
      }
      const sub =()=>{
        setsubcribe(true);
        console.log("subcribe--"+subcribe)
      }

    useEffect(() => {
        let mounted = true;
        setloading(true)
        async function fetchData() {
        setloading(true);
        await firebase.firestore()
        .collection("products")
        .onSnapshot((snapshot)=>{
            
            const data = snapshot.docs.map((doc)=>(
                {
                    id : doc.id,
                    ...doc.data()
                }
            ))
            console.log("b4 if--"+subcribe)
            if(subcribe){
                console.log("in if--"+subcribe)
            setproducts(data)
            setloading(false)
            }
        })
        }
        fetchData();
        return () => mounted = false;
    }, [subcribe])
    
    console.log("after getting bottom"+subcribe)
    return (
        <ProdContext.Provider value={{subcribe:subcribe,prodloading:loading, products: products, loading:loading , sub:sub , unsub:unsub}}>
            {props.children}
        </ProdContext.Provider>
    );
}
export default ProdContextProvider;*

And my products Component looks like this:

export default function Products(props){
    const {products , loading ,sub , unsub,subcribe}= useContext(ProdContext)
    const [selectid, setselectid] = useState("")
    const [ShowLoading, setShowLoading] = useState(true);
    const [showAlert2, setShowAlert2] = useState(false);
    const [redirect , setredirect] = useState(false)
    const [value, setValue] = useState(null);
    const [inputValue, setInputValue] = useState('');

    
 useEffect(() => {
     sub();
     console.log("product mound--"+subcribe)
 }, [])

 useEffect(() => {
    return () => {
        console.log("product unsub--"+subcribe)
        unsub();
        console.log("product unmound--"+subcribe)
    };
  }, []);

      if (redirect) {
        return <Redirect push to={{
            pathname: `/products/${selectid}`,  
        }} />;
      }
    return ( .........)}

Product Edit Component:

const Productedit = (props) => {

const {products,loading , subcribe} = useContext(ProdContext);
const { sub,unsub } = useContext(ProdContext);
  const [formData, setformData] = useState({});
  const {category} = useContext(CatContext)
  const [showLoading, setShowLoading] = useState(false);
  const [mainurl, setmainurl] = useState(null);
  const [imggal, setimggal] = useState([]);
  const [situation , setsituation] = useState("")
  const [redirect , setredirect] = useState(false)
  const [showAlert, setShowAlert] = useState(false);
  const [msg, setmsg] = useState(true);

 useEffect(() => {
     sub();
     console.log("productedit mound--"+subcribe)
     return () => unsub();
 }, [])
...........

Well I think the issue is that products component is still subscribed to getproduct provider even when it is unmounted but I cant get to solve the issue anyone can help

Error message Details and console log?

2

There are 2 answers

0
Saigeetha Sundar On

The issue is not related to Firestore rather this seems to be a common issue with react.

  • We just no need to update the state in the callback if the component is not mounted already.

  • It's better to check before updating the state by adding an if block in the async function

    if(mounted) {// Code inside the async tasks}

Please refer here [1] for additional information about this warning.

[1] https://www.debuggr.io/react-update-unmounted-component/#state-updates

(This should have been a comment as I don't have enough reputation hence posting as an answer)

Hope I understood the question right and the suggestion helps!

0
Piyush Rana On

You are not using mounted except only initializing it, you should not update your react state if your component is unmounted. You should do this inside your callback after successful API request:

if(mounted){
   // your state update goes here
}

But this is not the right though, what you should do is cancel your API request when component unmounts, I know little bit about request cancellation while using axios. You should search the web about API request cancellation in firebase or whatever you are using because if you are not updating your react state if component unmounts then still API request continue to run in the background and that is the main issue and that's why react throws this warning.