I am using redux-thunk
recently, and meet such case:
In signup action creator function, i wanna do history.push
after i dispatch a signup success action, the code may look like this:
// SignupAction.js
export const signupRequest = (userData) => {
return dispatch => {
dispatch(signupPending())
return axios.post('/api/user', userData)
.then(res => dispatch(signupSuccess()))
.then(() => {
// wanna do history.push('/') to the home page after successfully signup
})
.catch(error => dispatch(signupFailure(error.message)))
}
}
Right now i am confused, I am trying to put all the logic into one action, but there is no way to inject the history
into my signup action. I can give the signupRequest
the function a second argument, it could be the history
object itself: signupRequest(userData, history)
, or i can just pass a callback: signupRequest(userData, callback)
. However i am not sure which one is better.
There's also an alternative way to get history, i don't need put all logic in a single action, so the signup action
would just simply return a promise, and i will deal with it later in the component, in this case, accessing the history
would be quite straightforward:
// signupAction.js
export const signupRequest = (userData) => {
return dispatch => {
return axios.post('/api/users', userData);
}
}
// signupForm.js
export default class SignupForm extends Component {
// ...
handleSubmit = e => {
const userData = e.target.value
this.props.signupRequest(userData)
.then(() => this.props.dispatch(signupSuccess()))
.then(() => {
// now i can easily access history inside the component
this.props.history.push('/')
})
.catch(error => dispatch(signupFailure(error.message))) }
}
So which way should i follow, and is there any best practice to solve this problem?
Not sure if this is the best practice, but i see some people do it like this: solution
The key is to put history in a single file so that we can reference it and use it outside the component:
First create a histor
y object in a standalone file:
// history.js
import { createBrowserHistory } from 'history';
export default createBrowserHistory();
Then wrap it in the Router
component, be sure to use Router
rather than BrowserRouter
:
import { Router, Route } from 'react-router-dom';
import history from './history';
ReactDOM.render(
<Router history={history}>
...
</Router>
)
Finally in redux actionCreators we are able to import the history
object and use it:
// SignupAction.js
import history from './history'
export const signupRequest = (userData) => {
return dispatch => {
dispatch(signupPending())
return axios.post('/api/user', userData)
.then(res => dispatch(signupSuccess()))
.then(() => {
// we are reference/use the same `history` all the time by import it
history.push('/')
})
.catch(error => dispatch(signupFailure(error.message)))
}
}
So basically i still prefer to put logic inside the actionCreator, the component should only focus on UI rendering, the logic should be dealt by redux instead.