提问者:小点点

未安装组件上的react状态更新问题


嗯,当我想更新一个项目时,我调用UseEffect并对我的endpoint进行异步调用,但我想解决db中不存在id时的问题,它会抛出以下错误:警告:无法对未安装的组件执行React状态更新。这是一个no-op,但它表示应用程序中存在内存泄漏。要修复此问题,请取消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>
  )
}

共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>
  );
}

使用内部状态的演示(实时演示):

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>
  );
}