Reactjs useEffect-Can';t在未安装的组件上执行React状态更新

Reactjs useEffect-Can';t在未安装的组件上执行React状态更新,reactjs,react-hooks,Reactjs,React Hooks,我正在创建一个网站,列出了几个空缺职位 组件安装后,我想获得所有工作职位。因此,我使用了useffect。 我正在useffect中设置状态,我认为这是导致错误的原因: 警告:无法对已卸载的组件执行React状态更新 我想知道如何修复此警告。我不明白为什么我不能在useffect 我的组件 function MyComponent({changeType}) { const [user, setUser] = React.useState([]); const [position

我正在创建一个网站,列出了几个空缺职位

组件安装后,我想
获得所有工作职位。因此,我使用了
useffect
。 我正在
useffect
中设置状态,我认为这是导致错误的原因:

警告:无法对已卸载的组件执行React状态更新

我想知道如何修复此警告。我不明白为什么我不能在
useffect

我的组件

function MyComponent({changeType}) {
    const [user, setUser] = React.useState([]);
    const [positions, setPositions] = React.useState([]);

    async function getAllPositions(){
        let response = await axios("http://www.localhost:3000/api/v1/positions");
        setPositions(response.data)
    }


    useEffect( ()=> {
        let jwt = window.localStorage.getItem('jwt')
        let result = jwtDecode(jwt)
        setUser(result)
        changeType() # It is a function passing props to the parent of "MyComponent"
        getAllPositions()
        }, [],
    )
    return(
        <div>
         Something
        </div>
    )
}
函数MyComponent({changeType}){
const[user,setUser]=React.useState([]);
const[positions,setPositions]=React.useState([]);
异步函数getAllPositions(){
让响应=等待axios(“http://www.localhost:3000/api/v1/positions");
设置位置(响应数据)
}
useffect(()=>{
让jwt=window.localStorage.getItem('jwt')
让结果=jwtDecode(jwt)
设置用户(结果)
changeType()#它是一个向“MyComponent”的父级传递道具的函数
getAllPositions()
}, [],
)
返回(
某物
)
}

在异步调用后更新状态之前,您应该检查组件是否仍在装载

useEffect( ()=> {
       let unmounted = false
       async function getAllPositions(){
            let response = await  axios("http://www.localhost:3000/api/v1/positions");
            if(!unmounted)
                setPositions(response.data)
        }
        let jwt = window.localStorage.getItem('jwt')
        let result = jwtDecode(jwt)
        setUser(result)
        getAllPositions()
        return () => {
             unmounted = true
        }
}, [])

@亚历山大·维多尔·阿罗约的回答是正确的。您基本上需要确保在卸载组件时状态没有被更新

我试着按照hooks的精神重写他的答案,看看如何提取一些检查组件是否已安装的方法,以确定是否应该更新状态

import React, { useCallback, useRef, useState } from 'react';

const useIsMounted = () => {
  const isMounted = useRef(false);
  useEffect(() => {
    isMounted.current = true;
    return () => isMounted.current = false;
  }, []);
  return useCallback(() => isMounted.current, []);
};

const useAsyncState = (defaultValue) => {
  const isMounted = useIsMounted();
  const [value, setRawValue] = useState(defaultValue);
  const setValue = useCallback((newValue) => {
    if (isMounted()) {
      setRawValue(newValue);
    }
  }, []);
  return [value, setValue];
};

const getAllPositions = async () => {
  const response = await axios("http://www.localhost:3000/api/v1/positions");
  return response.data;
};

function MyComponent() {
  const [user, setUser] = useAsyncState([]);
  const [positions, setPositions] = useAsyncState([]);

  useEffect(async () => {
    const jwt = window.localStorage.getItem('jwt');
    const result = jwtDecode(jwt);
    setUser(result);
    setPositions(await getAllPositions());
  }, [setPositions, setUser]);

  return(
    <div>
      Something
    </div>
  );
}
import React,{useCallback,useRef,useState}来自'React';
常量useIsMounted=()=>{
const isMounted=useRef(false);
useffect(()=>{
isMounted.current=真;
return()=>isMounted.current=false;
}, []);
返回useCallback(()=>isMounted.current,[]);
};
常量UseAncyState=(默认值)=>{
const isMounted=useIsMounted();
const[value,setRawValue]=使用状态(defaultValue);
const setValue=useCallback((newValue)=>{
如果(isMounted()){
setRawValue(新值);
}
}, []);
返回[value,setValue];
};
const getAllPositions=async()=>{
常量响应=等待axios(“http://www.localhost:3000/api/v1/positions");
返回响应数据;
};
函数MyComponent(){
const[user,setUser]=useAncyState([]);
const[positions,setPositions]=UseAncyState([]);
useffect(异步()=>{
const jwt=window.localStorage.getItem('jwt');
const result=jwtDecode(jwt);
设置用户(结果);
设置位置(等待getAllPositions());
},[setPositions,setUser]);
返回(
某物
);
}

在Axios调用返回之前,
MyComponent
是否可能被其父组件卸载?我添加了函数
changeType
,用于将道具传递给
MyComponent
的父组件。您认为这可能是问题所在吗?您的意思是我在组件完全装入之前返回我的
异步调用
?不,您的异步调用可能在组件卸载时返回。如下所示:装载->异步调用->卸载->异步调用返回->状态更新。因此正确的方法应该是:装载-->异步调用-->检查组件是否装载-->如果是-->异步调用返回-->状态更新?