I have a simple useEffect hook in my 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 object contains a description. The description is another component with a text area. The idea is: when a user changes the description in the child component, the child component has a function (passed via props) to update the description.
So I pass updateDescription to my child component (Description) via props. Both useEffect and updateDescription are in my Task component, the Description component is basically stateless. What happens:
- user updates a description
- child component calls the function, it updates a record in my DB
- it gets the response from the API and calls setTask
- taskvariable is passed to- Descriptionvia props in- Task's- render, so they both get updated since the state of parent- Taskhas changed
- I see updated description
The only problem is that although it work, but when I do this, I can see this in console:
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.
(i've added the console.log just to see when it happens).
So I wanted to ask if this is a problem of me having async calls outside useEffect or maybe something else?
@Edit Description code (I removed all the unnecessary junk):
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
Funny thing, adding this to my Description solves the issue:
  useEffect(
    () => () => {
      setDescriptionContent("");
    },
    [content]
  );
Can anyone explain why?
