首页 > 解决方案 > useEffect 之外的 Rect 异步调用 - 内存泄漏

问题描述

我有一个简单的useEffect钩子Task

const TaskAD = ({ match }: TaskADProps) => {
  const { taskName } = match.params;
  const [task, setTask] = useState<TaskData | null>(null);
  const [loading, setLoading] = useState(true);

  const authCommunicator = authRequest();

  useEffect(() => {
    const getTask = async () => {
      const taskData = await authCommunicator
        .get(`/task/${taskName}`)
        .then((response) => response.data);
      setTask(taskData);
      setLoading(false);
    };
    getTask();
  }, []);

  if (loading || task == null) {
    return <Spinner centered />;
  }

  const updateDescription = async (content: string): Promise<boolean> => {
    const r = await authCommunicator
      .patch(`/task/${task.name}/`, {
        description: content,
      })
      .then((response) => {
        console.log("Setting Task data!");
        setTask(response.data);
        return true;
      })
      .catch(() => false);
    return r;
  };

  return (
    <ProjectEntity name={taskName}>
      <Space direction="vertical" size="small" style={{ width: "100%" }}>
        <StatusRow status="Open" />
        <TaskDetails task={task} />
        <Description content={task.description} onSubmit={updateDescription} />
        <Title level={2}>Subtasks:</Title>
        <Table dataSource={dataSource} columns={columns} />
      </Space>
    </ProjectEntity>
  );
};

Task对象包含描述。描述是另一个带有文本区域的组件。思路是:当用户更改子组件中的描述时,子组件有一个函数(通过 props 传递)来更新描述。

所以我通过道具传递updateDescription给我的子组件( )。Description两者useEffectupdateDescription都在我Task的组件中,该Description组件基本上是无状态的。怎么了:

唯一的问题是,虽然它可以工作,但是当我这样做时,我可以在控制台中看到:

Setting Task data!
Warning: 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.

(我添加了console.log只是为了看看它何时发生)。

所以我想问一下,这是否是我在外部进行异步调用的问题,useEffect还是其他原因?

@EditDescription代码(我删除了所有不必要的垃圾):

interface DescriptionProps {
  content: string;
  onSubmit?: (content: string) => Promise<boolean>;
  title?: string;
  rows?: number;
}

const Description = (props: DescriptionProps) => {
  const { content, onSubmit, title, rows } = props;
  const [descriptionContent, setDescriptionContent] = useState(content);
  const [expanded, setExpanded] = useState(true);
  const [editMode, setEditMode] = useState(false);
  const [descriptionChanged, setDescriptionChanged] = useState(false);
  const editable = onSubmit !== undefined;

  const resetDescription = () => {
    setDescriptionContent(content);
    setDescriptionChanged(false);
  };

  const changeDescription = (value: string) => {
    setDescriptionContent(value);
    setDescriptionChanged(true);
  };

  const descriptionTitle = (
    <>
      <S.DescriptionTitle>{title}</S.DescriptionTitle>
    </>
  );

  return (
    <Collapse
      defaultActiveKey={["desc"]}
      expandIcon={S.ExpandIcon}
      onChange={() => setExpanded(!expanded)}
    >
      <S.DescriptionHeader header={descriptionTitle} key="desc">
        <S.DescriptionContent
          onChange={(event): void => changeDescription(event.target.value)}
        />
        {descriptionChanged && onSubmit !== undefined ? (
          <S.DescriptionEditActions>
            <Space size="middle">
              <S.SaveIcon
                onClick={async () => {
                  setDescriptionChanged(!(await onSubmit(descriptionContent)));
                }}
              />
              <S.CancelIcon onClick={() => resetDescription()} />
            </Space>
          </S.DescriptionEditActions>
        ) : null}
      </S.DescriptionHeader>
    </Collapse>
  );
};

@Edit2

有趣的是,将其添加到我Description的解决方案中:

  useEffect(
    () => () => {
      setDescriptionContent("");
    },
    [content]
  );

谁能解释为什么?

标签: reactjsreact-hooks

解决方案


推荐阅读