快速切换页面后在 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>