react useEffect函数有问题

时间:2020-09-30 13:05:13

标签: reactjs react-hooks use-effect

我有这个地方的更新表格,我从后端获取其数据以在useEffect中添加初始输入,但出现此错误

无法在已卸载的组件上执行React状态更新。这是空操作,但它表明应用程序中发生内存泄漏。要修复,请取消使用useEffect清理功能中的所有订阅和异步任务。

我知道问题与更新状态之前卸载组件有关,但是我尝试了许多解决方案,但没有用。任何人都有一个解决办法

const UpdatePlace = () => {
const placeId = useParams().pId;
const [loadedPlace, setLoadedPlace] = useState();
// const [isLoading, setIsLoading] = useState(true);
const { error, sendRequest, clearError } = useHttpClient();

const [isLoading, formState, inputHandler, setFormData] = useForm(
  {
    title: {
      value: "",
      isValid: false,
    },
    description: {
      value: "",
      isValid: false,
    },
  },
  true
);

useEffect(() => {
  const fetchPlace = async () => {
    try {
      const res = await sendRequest(`/api/places/${placeId}`);
      await setLoadedPlace(res.data.place);
      setFormData(
        {
          title: {
            value: res.data.place.title,
            isValid: true,
          },
          description: {
            value: res.data.place.description,
            isValid: true,
          },
        },
        true
      );
    } catch (err) {}
  };
  fetchPlace();
}, [sendRequest, placeId, setFormData]);

if (!loadedPlace && !error) {
  return (
    <div className="center" style={{ maxWidth: "400px", margin: "0 auto" }}>
      <Card>
        <h2>No place found!</h2>
      </Card>
    </div>
  );
}

const placeUpdateSubmitHandler = (e) => {
  e.preventDefault();
  console.log(formState.inputs, formState.isFormValid);
};

return (
  <>
    {isLoading ? (
      <LoadingSpinner asOverlay />
    ) : error ? (
      <ErrorModal error={error} onClear={clearError} />
    ) : (
      <>
        <Title label="Update place" />
        <form className="place-form" onSubmit={placeUpdateSubmitHandler}>
          <Input
            element="input"
            type="text"
            id="title"
            label="Update title"
            validators={[VALIDATOR_REQUIRE()]}
            errorText="please enter valid title"
            onInput={inputHandler}
            initialValue={loadedPlace.title}
            initialValid={true}
          />
          <Input
            element="textarea"
            id="description"
            label="Update description"
            validators={[VALIDATOR_REQUIRE(), VALIDATOR_MINLENGTH(5)]}
            errorText="please enter valid description (min 5 chars) "
            onInput={inputHandler}
            initialValue={loadedPlace.description}
            initialValid={true}
          />
          <Button type="submit" disabled={!formState.isFormValid}>
            Update place
          </Button>
        </form>
      </>
    )}
  </>
);
};

2 个答案:

答案 0 :(得分:0)

您可以将useEffect与带有清除功能的[]一起使用,因为它将像这样执行最后一个:

useEffect(() => {
 return () => {
  console.log('cleaned up');
 }
},[])

答案 1 :(得分:0)

此错误表示从该页面导航离开后,您的请求完成,并且它尝试更新已经卸载的组件。您应该使用AbortController放弃请求。这样的事情应该起作用:

public ByteArrayInputStream generatePDF2(String htmlFile, String fontset) throws IOException {
        
        ByteArrayOutputStream pdf=new ByteArrayOutputStream();
        HtmlConverter.convertToPdf(htmlFile, pdf); 
        ByteArrayInputStream inputStream = new ByteArrayInputStream(pdf.toByteArray());

        

        return inputStream;
}

编辑:修复渲染时未定义的obj键/值

以上警告不会阻止您的组件渲染。初始化常量 loadedPlace 的方式将给您带来未定义的错误并阻止呈现组件。您将其初始化为null,但将其用作Input initialValue = {loadedPlace.title}中的对象。当您的组件尝试执行第一个渲染时,它将读取该值的状态,但无法找到键并中断。

尝试解决此问题:

useEffect(() => {
  const controller = new AbortController();
  const signal = controller.signal;

  const fetchPlace = async () => {
    try {
      const res = await fetch(`/api/places/${placeId}`, { signal }).then(response => {
    return response;
}).catch(e => {
    console.warn(`Fetch 1 error: ${e.message}`);
});
      await setLoadedPlace(res.data.place);
      setFormData(
        {
          title: {
            value: res.data.place.title,
            isValid: true,
          },
          description: {
            value: res.data.place.description,
            isValid: true,
          },
        },
        true
      );
    } catch (err) {}
  };
  fetchPlace();
  return () => {
    controller.abort();   
  };
}, [sendRequest, placeId, setFormData]);

始终确保使用对象时,在渲染时不要使用未定义的键。