Gilad Artzi
Gilad Artzi

Reputation: 3084

Redux - Change URL when an async action is dispatched

In my React/Redux application, I have some async actions. Let's say a user initiates a getData request to the server. Immediately a GET_DATA_REQUEST is being dispatched and the getData AJAX call is on its way to the server.

Upon success or failure, a GET_DATA_SUCCESS or GET_DATA_FAILURE actions are dispatched accordingly and the data is rendered to the UI.

Now, I want my application to push history state (using react-router-redux) as a reaction to the AJAX callback. Meaning, upon success, the users is "redirected" to another URL (route) the displays a different module that depends on the newly received data.

I realize it's a very bad idea to have this functionality in the reducer, as it won't be pure anymore (URL change is a side effect).

Any thoughts?

Thanks

Upvotes: 2

Views: 7713

Answers (2)

user3076685
user3076685

Reputation: 71

Another great way to do this. I learned this from this Udemy course, and I 100% recommend it.

Inside the component (a form you want to submit), put this form submit event handler, which will invoke the action.

submit(values) {
    this.props.xxxActionCreator(() => {
        this.props.history.push("/");//history is provided by react-route, .push("/") will direct app back to root path.
    });
}

render() { 
    <form onSubmit={this.submit.bind(this)} >
    .... </form>

Inside the action creator, put this

export default function xxxAction(callback) {
    const request = axios.get('...url').then(() => callback()); //here the function (callback) that was passed into this.props.xxxActionCreator() will be invoked.
    //.then() is provided by promise. This line of code means the callback (which redirects you to the root path) will be invoked, once the promise (async) is resolved.

    return { type: SOME_ACTION, payload: XXX };

GitHub demo here you can find the relevant code and the whole project. Which is kindly presented by Stephen Grider, a great teacher!

This is one way that doesn't put redirect into the state tree.

Upvotes: 7

QoP
QoP

Reputation: 28397

I believe this is a good way to handle your situation.

First of all, you should add a new property in your reducer to know if you want to redirect or not.

Something like this

const initialState = {
   ...
   redirect : false // You could use a String with the new url instead of true/false
   ....
}

switch ...
case GET_DATA_SUCCESS:
       return {
            ...state,
            redirect:true,
       }
case GET_DATA_FAILURE;
      return {
          ...state,
          redirect:false
      }

Then, in the component connected to your reducer, you should check the value of "redirect" in the componentDidUpdate function.

componentDidUpdate(){
        let {redirect} = this.props.yourReducerState;
        if(redirect === true){
            this.context.router.push("new-url");
        }
    }

Finally, you should reset "redirect" on componentWillUnmount

Hope it helps!

Upvotes: 9

Related Questions