【问题标题】:Problem with react state update on an unmounted component未安装组件上的反应状态更新问题
【发布时间】:2021-05-14 13:45:24
【问题描述】:

好吧,当我想更新一个项目时,我调用 UseEffect 并对我的端点进行异步调用,但是当 db 中不存在 id 时我想解决问题,它会抛出以下错误:警告:无法对未安装的组件执行 React 状态更新。这是一个空操作,但它表明您的应用程序中存在内存泄漏。要解决此问题,请在 useEffect 清理函数中取消所有订阅和异步任务。

export const AddOrUpdateItem = () => {
 
  const {id} = useParams();
  const [itemToUpdate, setItemToUpdate] = useState(null);
  const history = useHistory();
  
  useEffect(() => {
    if(id) {
      const fetchData = async() => {
        try {
          const resp = await axios.get(`${ITEMS_ENDPOINT}/${id}`);
          setItemToUpdate(resp.data);
          
        } catch (error) {
          console.log(error);
          history.push('/articulos'); //I think here is the problem
        }
      };
      fetchData();
    }
  }, [id]);

return (
    <Box mt={5}>
        <Paper elevation={7}>
            <Card className="card-root" variant="outlined">
                <CardContent>
                  <h2>{id !== undefined ? 'Actualizar artículo' : 'Registrar artículo'}</h2>
                  <hr/>
                  <ItemForm
                    id={id}
                    item={itemToUpdate}
                  />
                </CardContent>
            </Card>
        </Paper>
    </Box>
  )
}

【问题讨论】:

  • 如错误状态,使用清理功能:reactjs.org/docs/hooks-effect.html#effects-with-cleanup,你没有任何逻辑
  • 这意味着您可能在代码中某处的历史推送之后触发了setState(在useEffect 上运行)。我们可以看到您的组件的完整代码吗?

标签: reactjs axios react-hooks put


【解决方案1】:

最小的修复可能如下:

  useEffect(() => {
    const source = axios.CancelToken.source()

    if(id) {
      const fetchData = async() => {
        try {
          const resp = await axios.get(`${ITEMS_ENDPOINT}/${id}`, {cancelToken: source.token});
          setItemToUpdate(resp.data);
          
        } catch (error) {
          console.log(error);
          history.push('/articulos');
        }
      };
      fetchData();
    }

    return ()=> source.cancel() // <<<<<<<<<<<<<<
   }, [id]);

使用自定义挂钩 (Live demo):

import React from "react";
import { useState } from "react";
import {
  useAsyncEffect,
  CanceledError,
  E_REASON_UNMOUNTED
} from "use-async-effect2";
import cpAxios from "cp-axios";

function TestComponent(props) {
  const [text, setText] = useState("");

  const cancel = useAsyncEffect(
    function* () {
      setText("fetching...");
      try {
        const json = (yield cpAxios(props.url).timeout(props.timeout)).data;
        setText(`Success: ${JSON.stringify(json)}`);
      } catch (err) {
        CanceledError.rethrow(err, E_REASON_UNMOUNTED);
        setText(err.toString());
      }
    },
    [props.url]
  );

  return (
    <div className="component">
      <div>{text}</div>
      <button className="btn btn-warning" onClick={cancel}>
        Cancel request
      </button>
    </div>
  );
}

使用内部状态的演示 (Live demo):

import React from "react";
import { useAsyncEffect } from "use-async-effect2";
import cpAxios from "cp-axios";

function TestComponent(props) {
  const [cancel, done, result, err] = useAsyncEffect(
    function* () {
      return (yield cpAxios(props.url)).data;
    },
    { states: true, deps: [props.url] }
  );

  return (
    <div className="component">
      <div>
        {done ? (err ? err.toString() : JSON.stringify(result)) : "loading..."}
      </div>
      <button className="btn btn-warning" onClick={cancel} disabled={done}>
        Cancel async effect
      </button>
    </div>
  );
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-17
    • 1970-01-01
    • 2020-08-28
    • 2021-12-31
    相关资源
    最近更新 更多