React TypeScript:每次路由更改时如何调用 api 并设置状态
React TypeScript: How to call an api and set state each time the route changes
useEffect 每次更改路线时都会完美触发,当我从 useEffect 中调用 API,然后尝试使用结果设置状态时,我得到错误 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.
我试过用自调用函数调用 getPrice
但没有任何改变,我仍然得到同样的错误。
我应该使用 Suspense
??
import React, { useContext, useEffect, useState } from 'react';
const Calc: React.FC = () => {
interface StateInterface {
priceUsd: number;
}
const [price, setPrice] = useState<StateInterface>({
priceUsd: 0,
});
useEffect(() => {
const getPrice = async () => {
const response = await fetch('http://localhost:9999/price', {
body: JSON.stringify({
jwtToken: localStorage.getItem('jwtToken'),
}),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
method: 'POST',
});
if (response.status !== 400) {
const content = await response.json();
const priceUsd = content.price[0].priceUsd;
setPrice({ priceUsd });
}
};
getPrice();
}, []);
return (
<div>Calc</div>
)
}
export { Calc };
这个计算组件像这样加载到路由器中
import React, { useReducer } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import { globalContext, setGlobalContext } from './components/shell/context';
import { Layout } from './components/shell/layout';
import { defaultState, globalReducer } from './components/shell/reducer';
import { Calc } from './routes/calc';
import { NotFound } from './routes/not-found';
export function Router(): JSX.Element {
const [global, setGlobal] = useReducer(globalReducer, defaultState);
return (
<setGlobalContext.Provider value={{ setGlobal }}>
<globalContext.Provider value={{ global }}>
<BrowserRouter>
<Route
render={({ location }) => (
<Layout location={location}>
<Switch location={location}>
<Route exact path='/' component={Calc} />
<Route component={NotFound} />
</Switch>
</Layout>
)}
/>
</BrowserRouter>
</globalContext.Provider>
</setGlobalContext.Provider>
);
}
我遇到了同样的问题,你需要做的是在 useEffect
之外编写函数并调用该函数,就像这样。
const getPrice = async () => {
const response = await fetch('http://localhost:9999/price', {
body: JSON.stringify({
jwtToken: localStorage.getItem('jwtToken'),
}),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
method: 'POST',
});
if (response.status !== 400) {
const content = response.json();
const priceUsd = content.price[0].priceUsd;
setPrice({ priceUsd });
}
};
useEffect(() => {
getPrice();
}, []);
我无法从您分享的代码中看出任何明显的问题。但是错误表明,当调用 setPrice({ priceUsd })
时,<Calc />
组件已经卸载。
所以问题出在别处,它的父组件在获取逻辑完成之前取消呈现 <Calc />
。
我提出一个验证方法,diff见(+/-)符号:
import React, { useContext, useEffect, useState } from 'react';
const Calc: React.FC = () => {
interface StateInterface {
priceUsd: number;
}
const [price, setPrice] = useState<StateInterface>({
priceUsd: 0,
});
useEffect(() => {
const getPrice = async () => {
const response = await fetch('http://localhost:9999/price', {
body: JSON.stringify({
jwtToken: localStorage.getItem('jwtToken'),
}),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
method: 'POST',
});
if (response.status !== 400) {
const content = await response.json();
const priceUsd = content.price[0].priceUsd;
- setPrice({ priceUsd });
+ console.log('calling setPrice()', priceUsd);
}
};
getPrice();
+ return () => { console.log('I got cleaned-up') }
}, []);
return (
<div>Calc</div>
)
}
export { Calc };
如果我的理论是正确的,我们希望在 "calling setPrice()"
之前先在控制台中看到 "I got cleaned-up"
useEffect 每次更改路线时都会完美触发,当我从 useEffect 中调用 API,然后尝试使用结果设置状态时,我得到错误 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.
我试过用自调用函数调用 getPrice
但没有任何改变,我仍然得到同样的错误。
我应该使用 Suspense
??
import React, { useContext, useEffect, useState } from 'react';
const Calc: React.FC = () => {
interface StateInterface {
priceUsd: number;
}
const [price, setPrice] = useState<StateInterface>({
priceUsd: 0,
});
useEffect(() => {
const getPrice = async () => {
const response = await fetch('http://localhost:9999/price', {
body: JSON.stringify({
jwtToken: localStorage.getItem('jwtToken'),
}),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
method: 'POST',
});
if (response.status !== 400) {
const content = await response.json();
const priceUsd = content.price[0].priceUsd;
setPrice({ priceUsd });
}
};
getPrice();
}, []);
return (
<div>Calc</div>
)
}
export { Calc };
这个计算组件像这样加载到路由器中
import React, { useReducer } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import { globalContext, setGlobalContext } from './components/shell/context';
import { Layout } from './components/shell/layout';
import { defaultState, globalReducer } from './components/shell/reducer';
import { Calc } from './routes/calc';
import { NotFound } from './routes/not-found';
export function Router(): JSX.Element {
const [global, setGlobal] = useReducer(globalReducer, defaultState);
return (
<setGlobalContext.Provider value={{ setGlobal }}>
<globalContext.Provider value={{ global }}>
<BrowserRouter>
<Route
render={({ location }) => (
<Layout location={location}>
<Switch location={location}>
<Route exact path='/' component={Calc} />
<Route component={NotFound} />
</Switch>
</Layout>
)}
/>
</BrowserRouter>
</globalContext.Provider>
</setGlobalContext.Provider>
);
}
我遇到了同样的问题,你需要做的是在 useEffect
之外编写函数并调用该函数,就像这样。
const getPrice = async () => {
const response = await fetch('http://localhost:9999/price', {
body: JSON.stringify({
jwtToken: localStorage.getItem('jwtToken'),
}),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
method: 'POST',
});
if (response.status !== 400) {
const content = response.json();
const priceUsd = content.price[0].priceUsd;
setPrice({ priceUsd });
}
};
useEffect(() => {
getPrice();
}, []);
我无法从您分享的代码中看出任何明显的问题。但是错误表明,当调用 setPrice({ priceUsd })
时,<Calc />
组件已经卸载。
所以问题出在别处,它的父组件在获取逻辑完成之前取消呈现 <Calc />
。
我提出一个验证方法,diff见(+/-)符号:
import React, { useContext, useEffect, useState } from 'react';
const Calc: React.FC = () => {
interface StateInterface {
priceUsd: number;
}
const [price, setPrice] = useState<StateInterface>({
priceUsd: 0,
});
useEffect(() => {
const getPrice = async () => {
const response = await fetch('http://localhost:9999/price', {
body: JSON.stringify({
jwtToken: localStorage.getItem('jwtToken'),
}),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
method: 'POST',
});
if (response.status !== 400) {
const content = await response.json();
const priceUsd = content.price[0].priceUsd;
- setPrice({ priceUsd });
+ console.log('calling setPrice()', priceUsd);
}
};
getPrice();
+ return () => { console.log('I got cleaned-up') }
}, []);
return (
<div>Calc</div>
)
}
export { Calc };
如果我的理论是正确的,我们希望在 "calling setPrice()"
"I got cleaned-up"