挂钩反应无法正确更新我的状态

时间:2019-11-13 14:07:06

标签: reactjs react-functional-component

我正在尝试以某种形式加载从API获得的一些数据,但是状态挂钩似乎做错了。

在下面的代码中,我使用钩子定义一个employee和employeeId。 之后,我尝试使用useEffect来模仿类组件中的componentDidMount函数。

在这里,我会检查url中是否包含参数,并使用setEmployeeId(props.match.params.employeeId)更新employeeId状态。

问题是,我的状态值没有更新,我的整个流程都崩溃了。

请记住,我宁愿为此使用功能组件。

export default function EmployeeDetail(props) {
    const [employeeId, setEmployeeId] = useState<number>(-1);
    const [isLoading, setIsLoading] = useState(false);
    const [employee, setEmployee] = useState<IEmployee>();

    useEffect(() => componentDidMount(), []);

    const componentDidMount = () => {
        // --> I get the correct id from the params
        if (props.match.params && props.match.params.employeeId) { 
            setEmployeeId(props.match.params.employeeId)
        }

        // This remains -1, while it should be the params.employeeId
        if (employeeId) {
            getEmployee();
        }
    }

    const getEmployee = () => {
        setIsLoading(true);
        EmployeeService.getEmployee(employeeId)    // --> This will return an invalid employee
            .then((response) => setEmployee(response.data))
            .catch((err: any) => console.log(err))
            .finally(() => setIsLoading(false))
    }

    return (
        <div>
            ...
        </div>
    )
}

3 个答案:

答案 0 :(得分:0)

useEffect返回的函数将在onmount上调用。由于您使用的是隐式收益,因此您的情况就是如此。如果需要在挂载上调用它,则需要调用它而不是返回它。

编辑:由于还设置了员工ID,因此需要在依赖项数组中进行跟踪。这是因为,React中的设置状态是异步的,并且更新的状态值仅在下一个渲染器上可用。

useEffect(() => {
  componentDidMount()
}, [employeeId]);

一种替代方法是直接通过getEmployee方法使用props的数据:

useEffect(() => {
  componentDidMount()
}, []);

const componentDidMount = () => {
  if (props.match.params && props.match.params.employeeId) {
    setEmployeeId(props.match.params.employeeId)
    getEmployee(props.match.params.employeeId);
  }
}

const getEmployee = (employeeId) => {
  setIsLoading(true);
  EmployeeService.getEmployee(employeeId);
    .then((response) => setEmployee(response.data))
    .catch((err: any) => console.log(err))
    .finally(() => setIsLoading(false))
}

答案 1 :(得分:0)

来自setEmployeeId的新值可能会在下一个渲染中可用。

您正在运行的代码是同一渲染的一部分,因此尚未设置该值。

由于您使用的是同一函数,请使用已经拥有的值:props.match.params.employeeId

请记住,当您调用set*时,是在指示React将更新排队。当React决定时,更新可能会发生。

如果您希望getEmployee仅运行一次currentEmployeeId更改,请考虑使其生效:

useEffect(() => {
   getEmployee(currentEmployeeId);
}, [currentEmployeeId])

答案 2 :(得分:0)

问题似乎是您尝试在更新之前使用“已更新”状态。我建议您使用类似的

export default function EmployeeDetail(props) {
    const [employeeId, setEmployeeId] = useState<number>(-1);
    const [isLoading, setIsLoading] = useState(false);
    const [employee, setEmployee] = useState<IEmployee>();

    useEffect(() => componentDidMount(), []);

    const componentDidMount = () => {
        // --> I get the correct id from the params
        let currentEmployeeId
        if (props.match.params && props.match.params.employeeId) { 
            currentEmployeeId = props.match.params.employeeId
            setEmployeeId(currentEmployeeId)
        }

        // This was remaining -1, because state wasn't updated
        if (currentEmployeeId) {
            getEmployee(currentEmployeeId);
            //It's a good practice to only change the value gotten from a 
            //function by changing its parameter
        }
    }

    const getEmployee = (id: number) => {
        setIsLoading(true);
        EmployeeService.getEmployee(id)  
            .then((response) => setEmployee(response.data))
            .catch((err: any) => console.log(err))
            .finally(() => setIsLoading(false))
    }

    return (
        <div>
            ...
        </div>
    )
}