How to push to History in React Router v4?
#1
I've recently upgraded to React Router v4 from v3 and have been encountering issues when trying to programmatically navigate to different routes after a successful callback, particularly with Redux actions. In the previous version of React Router, I would use `browserHistory.push('/somepath')` to achieve this, but since they have removed `browserHistory` in v4, I am not quite sure about the right way to proceed.
Here's how my action creators looked in React Router v3 when making a post request and then redirecting:

Code:
dispatch({
                type: 'AUTH_USER'
            });
            // Redirect to the cart page
            browserHistory.push('/cart'); // This doesn't work in React Router v4
        });
}

Can anyone suggest the correct approach for redirecting in React Router v4 within Redux actions?
Reply
#2
React Router v4 introduced a new declarative approach and got rid of `browserHistory`. Instead, they use a `history` object that comes with various routers such as `<BrowserRouter>` and `<Router>`. You would need to either pass this `history` object down to your action creators or use a helper method. Here's how you might do it with `withRouter` and programmatically navigate with `this.props.history.push` in a component.

Code:
myFunction = () => {
        this.props.addProduct(this.props.productDetails)
            .then(() => {
                this.props.history.push('/cart');
            });
    };
    // ... rest of the component
}
export default withRouter(MyComponent);

But this means you need to handle the redirect inside a component, not in the Redux action. If you want to keep the redirect inside the Redux action you might need to use a custom history object.
Reply
#3
That's right. For handling redirects inside actions, you'll need to create your own `history` object that you can use both in your Redux actions and your React Router setup. Create a `history.js` file:


Then use this custom history in your Router setup:

Code:
<Router history = {
        history
    } > {
        /* your routes */ }
</Router>

Now, you can import and use this custom history object in your actions:

Code:
dispatch({
                type: 'AUTH_USER'
            });
            history.push('/cart');
        });
}

Make sure you replace the old `<BrowserRouter>` with the new `<Router>` setup with your custom history.
Reply
#4
That’s a solid approach. Just keep in mind that handling side effects like navigation in your actions is not always considered best practice, as it can make your actions less predictable and harder to test. A better approach might be to handle the promise in your component and redirect after the action is dispatched.
Here's the updated code with the required import statements.

Code:
// MyComponent.js:
import React from 'react';
import {
    connect
} from 'react-redux';
import {
    withRouter
} from 'react-router-dom';
import {
    addProduct
} from '../actions';
class MyComponent extends React.Component {
    // ... component logic
    myFunction = props => {
        this.props.addProduct(props).then(() => {
            this.props.history.push('/cart');
        });
    };
    // ... rest of the component
}
const mapDispatchToProps = dispatch => ({
    addProduct: productDetails => dispatch(addProduct(productDetails))
});
export default withRouter(connect(null, mapDispatchToProps)(MyComponent));
// actions/index.js:
import axios from 'axios';
import history from '../history';
export function addProduct(props) {
    return dispatch =>
        axios.post(`/cart`, props)
        .then(response => {
            dispatch({
                type: 'AUTH_USER'
            });
            history.push('/cart');
        });
}
// Router setup in App.js or index.js:
import {
    Router
} from 'react-router-dom';
import history from './history'; <Router history = {
        history
    } > {
        /* your routes */ }
</Router>
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)