如何取消 useEffect 清理函数中的所有订阅和异步任务?
Posted
技术标签:
【中文标题】如何取消 useEffect 清理函数中的所有订阅和异步任务?【英文标题】:How to cancel all subscriptions and asynchronous tasks in a useEffect cleanup function? 【发布时间】:2021-01-28 13:36:28 【问题描述】:当我在反应功能组件中调用第二个 API 时,我无法更新状态。第一个 API 调用在 useEffect 内部,第二个 API 调用在用户单击按钮时完成。当第二个 API 调用完成时,react 会抛出此错误“无法在未安装的组件上执行 React 状态更新。这是一个无操作,但它表明您的应用程序中存在内存泄漏。要修复,取消所有订阅和异步useEffect 清理函数中的任务。” 并且状态没有更新,我想在第二次 API 调用之后设置状态。如何解决这个问题?
我的代码:
const AddNewProduct = () =>
const [productName, setProductName] = useState("");
const [originalPrice, setOriginalPrice] = useState("");
const [newPrice, setNewPrice] = useState("");
const [category, setCategory] = useState("");
const [description, setDescription] = useState("");
const [categoriesArray, setCategoriesArray] = useState([]);
const [isLogin, setIsLogin] = useState([]);
const [id, setId] = useState("");
useEffect(() =>
const getCategoriesData = async () =>
const Data = await fetchCategoriesApi();
setIsLogin(Data.data.login);
setCategoriesArray(Data.data.data);
console.log(Data);
;
getCategoriesData();
, []);
const handleCategoryClick = (id) =>
setCategory(id);
console.log(id);
;
const handleNextClick = async () =>
const postApi = "https://fliqapp.xyz/api/seller/products";
try
const post = await axios
.post(
postApi,
product_name: productName,
product_desc: description,
product_price: originalPrice,
product_cat: category,
,
headers:
Authorization: `Bearer $localStorage.getItem("token")`,
,
)
.then((response) =>
setId(response.data.data.product_id);
console.log(id);
console.log(response);
);
catch (error)
return error;
console.log("clicked");
;
return (
<>
<div className=styles.container>
<div className=styles.blank></div>
<input
type="text"
className=styles.input_field
placeholder="Product name*"
onChange=(e) => setProductName(e.target.value)
/>
<input
type="text"
className=styles.input_field
placeholder="original price*"
onChange=(e) => setOriginalPrice(e.target.value)
/>
<input
type="text"
className=styles.input_field
placeholder="new price"
onChange=(e) => setNewPrice(e.target.value)
/>
<select
name="parent category"
id="parentcategory"
className=styles.dropdown
defaultValue="DEFAULT"
onChange=(e) => handleCategoryClick(e.target.value)
>
<option value="DEFAULT" disabled>
select category
</option>
isLogin &&
categoriesArray.map((item, index) => (
<option value=item.id key=index>
item.cat_name
</option>
))
</select>
<textarea
type="textarea"
className=styles.input_field
placeholder="Description"
rows="4"
onChange=(e) => setDescription(e.target.value)
/>
<Link
to=
pathname: `/add_image/$id`,
className=styles.btn
onClick=handleNextClick
disabled
>
Next
</Link>
<div className=styles.header>
<h1 className=styles.heading_normal>Add new product</h1>
</div>
</div>
</>
);
;
【问题讨论】:
【参考方案1】:您需要将Link
更改为Button
并手动导航到其他路线,因为路线/add_image/$id
中使用的id
来自第二个Api 调用。
原因:因为当您单击链接时,它会触发 axios 请求并更改您的应用程序的路由,因此当前组件被卸载并安装了新的路由组件,在这种情况下您的 axios 响应卷土重来并尝试
setState
on unmounted组件。
// import
import useHistory from 'react-router-dom';
// inside component
const history = useHistory();
// click handler
const handleNextClick = async () =>
// ...axiosrequest
.then((response) =>
setId(response.data.data.product_id); // may be not needed now
const id = response.data.data.product_id;
history.push(`/add_image/$id`);
// button
<button
className=styles.btn
onClick=handleNextClick
>
Next
</button>
通过这种方式,您只需在从服务器获得正确响应后更改一次路由,并根据response ID
更新您的路由。
为了更好的用户体验,您可以在执行 axios ajax 请求的同时显示加载。
如有任何疑问,请发表评论。
【讨论】:
以上是关于如何取消 useEffect 清理函数中的所有订阅和异步任务?的主要内容,如果未能解决你的问题,请参考以下文章
删除组件后如何清理react js中的useEffect函数
如何使用钩子清理 componentDidUpdate 中的异步函数