在 redux-thunk 中发送注册成功操作后如何对另一个页面执行 history.push

how to do history.push to another page after dispatch a signup success action in redux-thunk

我最近在用redux-thunk,遇到这样的情况:

在注册操作创建者函数中,我想在发送注册成功操作后执行 history.push,代码可能如下所示:

// 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)))
  }
}

现在我很困惑,我试图将所有逻辑放入一个操作中,但是无法将 history 注入我的注册操作中。我可以给 signupRequest 函数第二个参数,它可以是 history 对象本身:signupRequest(userData, history),或者我可以只传递一个回调:signupRequest(userData, callback)。但是我不确定哪个更好。

还有另一种获取历史记录的方法,我不需要将所有逻辑放在一个动作中,所以 signup action 只是 return 一个承诺,我会处理它稍后在组件中,在这种情况下,访问 history 将非常简单:

// 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)))  }
}

那么我应该采用哪种方式,有什么最佳实践可以解决这个问题吗?

不确定这是否是最佳做法,但我看到有人这样做:

关键是把history放在一个文件里,这样我们就可以在组件外引用和使用它:

首先在独立文件中创建一个 history 对象:

// history.js
import { createBrowserHistory } from 'history';

export default createBrowserHistory();

然后包裹在Router组件中,一定要用Router而不是BrowserRouter:

import { Router, Route } from 'react-router-dom';
import history from './history';

ReactDOM.render(
  <Router history={history}>
    ...
  </Router>
)

最后在 redux actionCreators 中我们可以导入 history 对象并使用它:

// 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)))
  }
}

所以基本上我还是更喜欢把逻辑放在actionCreator里面,组件应该只关注UI渲染,逻辑应该由redux来处理。