快速切换页面后在 axios 调用中反应 setState
React setState in an axios call after switching pages quickly
假设我在A组件中,在A组件中,我发出了一个axios/api调用请求。当 axios 调用正在处理时,我移动到组件 B,然后很快回到组件 A(正在执行 axios 调用的地方)。当我收到响应并尝试设置状态时,控制台显示错误
“无法在未安装的组件上设置状态”,
即使组件已安装。我确实尝试了安装和卸载检查,但它总是显示组件已安装。我尝试了一切,但没有任何效果。我是 React 的新手,需要帮助
您应该在等待响应时不会卸载的父组件中进行 api 调用。然后你可以将结果存储在父组件状态中,并将值作为 prop 传递给组件 A。然后组件 A 成为一个无状态功能组件,根据 prop 的值呈现自身。
您可以检查组件是否安装在 useEffect
钩子内,另外
对于 class 组件,您可以将类似的逻辑放入 componentDidMount()
componentWillUnmount()
例子
const { useState, useEffect, Component } = React;
const { Switch, Link, Route, HashRouter, useLocation, useHistory } = ReactRouterDOM;
class Component1Class extends Component {
constructor(props) {
super(props);
this.isUnmounted = false;
this.cancelToken = axios.CancelToken.source();
this.state = {
url: ''
}
}
componentDidMount() {
axios.get("https://i.picsum.photos/id/439/200/300.jpg", { cancelToken: this.cancelToken.token })
.then(response => {
if(this.isUnmounted) {
return;
}
this.setState({url: response.request.responseURL});
}).catch((err) => {
if (axios.isCancel(err)) {
console.log('Previous request canceled, new request is in proccess', err.message);
} else {
}
});
}
componentWillUnmount() {
this.isUnmounted = true;
this.cancelToken.cancel();
}
render() {
return <div>
<img src={this.state.url} alt="image"/>
</div>
}
}
const Component1 = () => {
const [url, setUrl] = useState('');
useEffect(() => {
let isUnmounted = false;
let cancelToken = axios.CancelToken.source();
axios.get("https://i.picsum.photos/id/439/200/300.jpg", { cancelToken: cancelToken.token })
.then(response => {
if(isUnmounted) {
return;
}
setUrl(response.request.responseURL);
}).catch((err) => {
if (axios.isCancel(err)) {
console.log('Previous request canceled, new request is in proccess', err.message);
} else {
}
});
return () => {
isUnmounted = true;
cancelToken.cancel();
}
}, [])
return <div>
<img src={url} alt="image"/>
</div>
}
const Component2 = () => {
return <div></div>
}
const App = () => {
return <div>
<div>
<Link to="/1">Component1</Link>
</div>
<div>
<Link to="/2">Component2</Link>
</div>
<Switch>
<Route path="/1" component={Component1Class}/>
<Route path="/2" component={Component2}/>
<Route component={Component1Class}/>
</Switch>
</div>
}
ReactDOM.render(
<HashRouter>
<App />
</HashRouter>,
document.getElementById('root')
);
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script src="https://unpkg.com/browse/react-router@3.0.2/umd/react-router.js"></script>
<script src="https://unpkg.com/react-router-dom@5.2.0/umd/react-router-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.js"></script>
<div id="root"></div>
假设我在A组件中,在A组件中,我发出了一个axios/api调用请求。当 axios 调用正在处理时,我移动到组件 B,然后很快回到组件 A(正在执行 axios 调用的地方)。当我收到响应并尝试设置状态时,控制台显示错误 “无法在未安装的组件上设置状态”, 即使组件已安装。我确实尝试了安装和卸载检查,但它总是显示组件已安装。我尝试了一切,但没有任何效果。我是 React 的新手,需要帮助
您应该在等待响应时不会卸载的父组件中进行 api 调用。然后你可以将结果存储在父组件状态中,并将值作为 prop 传递给组件 A。然后组件 A 成为一个无状态功能组件,根据 prop 的值呈现自身。
您可以检查组件是否安装在 useEffect
钩子内,另外
对于 class 组件,您可以将类似的逻辑放入 componentDidMount()
componentWillUnmount()
例子
const { useState, useEffect, Component } = React;
const { Switch, Link, Route, HashRouter, useLocation, useHistory } = ReactRouterDOM;
class Component1Class extends Component {
constructor(props) {
super(props);
this.isUnmounted = false;
this.cancelToken = axios.CancelToken.source();
this.state = {
url: ''
}
}
componentDidMount() {
axios.get("https://i.picsum.photos/id/439/200/300.jpg", { cancelToken: this.cancelToken.token })
.then(response => {
if(this.isUnmounted) {
return;
}
this.setState({url: response.request.responseURL});
}).catch((err) => {
if (axios.isCancel(err)) {
console.log('Previous request canceled, new request is in proccess', err.message);
} else {
}
});
}
componentWillUnmount() {
this.isUnmounted = true;
this.cancelToken.cancel();
}
render() {
return <div>
<img src={this.state.url} alt="image"/>
</div>
}
}
const Component1 = () => {
const [url, setUrl] = useState('');
useEffect(() => {
let isUnmounted = false;
let cancelToken = axios.CancelToken.source();
axios.get("https://i.picsum.photos/id/439/200/300.jpg", { cancelToken: cancelToken.token })
.then(response => {
if(isUnmounted) {
return;
}
setUrl(response.request.responseURL);
}).catch((err) => {
if (axios.isCancel(err)) {
console.log('Previous request canceled, new request is in proccess', err.message);
} else {
}
});
return () => {
isUnmounted = true;
cancelToken.cancel();
}
}, [])
return <div>
<img src={url} alt="image"/>
</div>
}
const Component2 = () => {
return <div></div>
}
const App = () => {
return <div>
<div>
<Link to="/1">Component1</Link>
</div>
<div>
<Link to="/2">Component2</Link>
</div>
<Switch>
<Route path="/1" component={Component1Class}/>
<Route path="/2" component={Component2}/>
<Route component={Component1Class}/>
</Switch>
</div>
}
ReactDOM.render(
<HashRouter>
<App />
</HashRouter>,
document.getElementById('root')
);
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script src="https://unpkg.com/browse/react-router@3.0.2/umd/react-router.js"></script>
<script src="https://unpkg.com/react-router-dom@5.2.0/umd/react-router-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.js"></script>
<div id="root"></div>