Abort request while navigating away from the compo

2019-04-10 09:01发布

问题:

I am using react, redux and react-router. One of my page is making an API request and showing the data. It works fine. What I want to know is, if the API request is not yet finished, and the user navigates to another route, I want to be able to abort the request.

I am assuming I should dispatch some action in the componentWillUnmount. Just not able to understand how will it work. Something like...

componentWillUnmount() {
    this.props.dispatch(Actions.abortRequest());
}

And I'll store the xhr reference somewhere in the action. Not sure if this is the correct approach or not (I think not), can someone point me in the right direction?

回答1:

I don't think storing xhr in action is correct.
Actions should be serializable, and XMLHttpRequest definitely isn't.

Instead, I'd use Redux Thunk to return a custom object from my action creator, and do something like this:

function fetchPost(id) {
  return dispatch => {
    // Assuming you have a helper to make requests:
    const xhr = makePostRequest(id);

    dispatch({ type: 'FETCH_POST_REQUEST', response, id });

    // Assuming you have a helper to attach event handlers:
    trackXHR(xhr,
      (response) => dispatch({ type: 'FETCH_POST_SUCCESS', response, id }),
      (err) => dispatch({ type: 'FETCH_POST_FAILURE', err, id })
    );

    // Return an object with `abort` function to be used by component
    return { abort: () => xhr.abort() };     
  };
}

Now you can use abort from your component:

componentDidMount() {
  this.requests = [];
  this.requests.push(
    this.props.dispatch(fetchPost(this.props.postId))
  );
}

componentWillUnmount() {
  this.requests.forEach(request => request.abort());
}


回答2:

I don't see anything wrong with this approach. What you're holding in the store is the global application state; if you want to change the xhr behaviour based on other actions then you need to store that state somewhere.

I've seen plenty of examples where the store would look something like this:

{
  isFetching: false,
  items: [],
  lastUpdated: null
};

The isFetching state is then used to display a loading spinner or prevent multiple xhr requests being sent. I'd see your use and storing the xhr reference and being able to abort it is just an extension of this.