Невозможно выполнить обновление состояния React на отключенном компоненте. (UseEffect) (Context API) (REACT.js)

Итак, я получаю это предупреждение: -

*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)*

Что ж, это происходит в компоненте продуктов, когда я перенаправляюсь в компонент редактирования продукта! Компонент продуктов используется для перечисления всех продуктов, а редактирование продукта используется для редактирования сведений о продукте, и оба эти компонента подключены к одному контекстному API с помощью useContext. Мой поставщик API контекста выглядит так

*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;*

А мой компонент продуктов выглядит так:

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 ( .........)}

Компонент редактирования продукта:

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();
 }, [])
...........

Что ж, я думаю, проблема в том, что компонент продуктов все еще подписан на поставщика getproduct, даже когда он отключен, но я не могу решить проблему, которую может помочь

Подробное сообщение об ошибке и журнал консоли?


person Amal Shyjo    schedule 09.10.2020    source источник


Ответы (2)


Проблема не связана с Firestore, скорее, это обычная проблема с react.

  • Нам просто не нужно обновлять состояние в обратном вызове, если компонент еще не смонтирован.

  • Лучше проверить перед обновлением состояния, добавив блок if в асинхронную функцию.

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

Пожалуйста, обратитесь сюда [1] для получения дополнительной информации об этом предупреждении.

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

(Это должен был быть комментарий, поскольку у меня недостаточно репутации, поэтому я пишу как ответ)

Надеюсь, я правильно понял вопрос, и предложение помогает!

person Saigeetha Sundar    schedule 19.10.2020

Вы не используете mounted, за исключением его инициализации, вам не следует обновлять свое состояние реакции, если ваш компонент отключен. Вы должны сделать это внутри своего обратного вызова после успешного запроса API:

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

Но это неправильно, вам следует отменить запрос API при отключении компонента. Я немного знаю об отмене запроса при использовании axios. Вам следует поискать в Интернете об отмене запроса API в firebase или о том, что вы используете, потому что, если вы не обновляете свое состояние реакции, если компонент отключается, тогда запрос API все равно продолжает выполняться в фоновом режиме, и это основная проблема, и поэтому реакция выдает это предупреждение.

person Piyush Rana    schedule 19.10.2020