about 2 years ago

在 Router 切換路徑時會發生

Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the undefined component.

主要是在執行 Ajax 執行 response 函數時
因為 component 已經 unmounted
導致 setState 執行時所造成的錯誤

官方有推薦的做法
https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html

而消極的做法

constructor(props) {
      super(props);
      const CancelToken = axios.CancelToken;
      this.isUnmounted = false; // 建立一個tag 來監測 component 是否已經 unmounted
}
...
..
componentWillUnmount() {
    this.isUnmounted = true;
}
...
_processResponse(response) {
  if(this.isUnmounted) { // 檢視是否要執行 setState
    return;
  }
  this.setState({
    visible: false,
  });
}

或使用 axios CancelToken 搭配 Hoc 來取消 request

const AxiosHoc = (Component) => class extends React.Component {
    constructor(props) {
      super(props);
      const CancelToken = axios.CancelToken;
      this.source = CancelToken.source();
    }  
    _get = (url, params, thenFunction) => {
      axios.get(url, { params : params, cancelToken: this.source.token })
      .then(thenFunction).catch(this._errorCatch);
    }
    _post = (url, params, thenFunction) => {
      axios.post(url, Object.assign(params, { cancelToken: this.source.token }))
      .then(thenFunction).catch(this._errorCatch);
    }
    _put = (url, params, thenFunction) => {
      axios.put(url, Object.assign(params, { cancelToken: this.source.token }))
      .then(thenFunction).catch(this._errorCatch);
    }
    _delete = (url, params, thenFunction) => {
      axios.delete(url, { params : params, cancelToken: this.source.token })
      .then(thenFunction).catch(this._errorCatch);
    }    
    _errorCatch = (error) => {
      if (axios.isCancel(error)) {
        console.log(error.message);
      } else {
        console.log(error);
      }
    }
    componentWillUnmount() {
        this.source.cancel(`${Component.name} Request Operation canceled by source`);
    }    
    render() {
      return <Component {...this.props} {...this.state}
              get={this._get}
              post={this._post}
              put={this._put}
              delete={this._delete}
               />
    }
  }

使用方式

class UserEditForm extends Component {
...
..
.
    addUser = () => {
        this.props.post('users', this.state.values, this._addResponse);
    }
    _addResponse = (response) => {
    ...
    ..
    }
}
export default AxiosHoc(UserEditForm);
← 使用 create-react-app 和 React Router 做 code splitting React 使用 Render prop 取代 HOCs →
 
comments powered by Disqus