【问题标题】:Call function after dispatch from redux has finished从 redux 调度完成后调用函数
【发布时间】:2018-05-13 21:44:52
【问题描述】:

到处都是,但我对redux-thunkreact-router的想法还不够,但我没有得到这个看似简单的想法:

在操作完成分发到商店后,通过<Route/>history.push('/') 以编程方式调用路由更改,这会在按下按钮时发生。

const LoggerRedux = ({stateProp, LogIn}) => {
    return(
      <div>
        <h2>Here is the button. Use this to login</h2>
        <Route render={({ history}) => (
          <button
            type='button'
            onClick={

            //Something that calls {LogIn}
            //and then the history.push('/')

            }
            >
            Log yo Arse Inn
          </button>
        )}>

        </Route>
      </div>
    )
}

const mapStateToProps = (state) => {
  return {
    stateProp : state
  }
}
const mapDispatchToProps = (dispatch) => {
  return {
    LogIn : () => dispatch({
      type : 'AUTHENTICATE'
    }),
    LogOut : (bool) => dispatch({
      type : 'LOGGED_OUT',
      bool
    })
  }
}
const LoginConn = connect( mapStateToProps, mapDispatchToProps)(LoggerRedux);

我提到/标记的所有事情的通俗解释和示例也很好

【问题讨论】:

    标签: reactjs redux react-router react-redux redux-thunk


    【解决方案1】:

    我想在这里突出显示这部分...

    <Route render={({ history}) => (
      <button
        type='button'
        onClick={
    
        //Something that calls {LogIn}
        //and then the history.push('/')
    
        }
        >
        Log yo Arse Inn
      </button>
    )}>
    
    </Route>
    

    您想调用 Login 并将历史记录推送到应用程序的根目录。 你有几个选择:

    1. 在你的 Login 函数中调用函数 history.push('/'),这看起来在你的 reducer AUTHENTICATE 函数中。

    2. 在成功验证后调度调用history.push 的操作 看看redux-promiseredux-sagaredux-thunk 做起来有点棘手,但这是可能的

    目前我不会尝试以任何其他方式执行此操作,因为您依赖于登录(通过 redux 调用,所以我想将逻辑保留在那里,即使它是客户端重定向)。

    【讨论】:

    • 这是为了在实施前学习,但稍后会涉及到那些 .then() 承诺的 axios,所以我可以放心地假设在那里执行 history.push('/')
    • 我也不能,因为在操作过程中没有调用 history 道具,我发现这不是将 history 作为道具传递给的最佳实践功能
    【解决方案2】:

    根据这个 stackoverflow 答案:Is store.dispatch in Redux synchronous or asynchronous,redux 调度函数是同步的,因此,你可以这样做:

    LogIn();
    history.push("/");
    

    【讨论】:

    • 你是对的,如果你不使用 thunk,它们是同步的。但是,一旦你使用了 thunk,它们就不再是同步的了。
    【解决方案3】:

    让你的动作创建者返回一个承诺。这样,当您调用它时,您可以使用 .then() 并在您的 then 处理程序中将新地址推送到历史记录。

    Thunk 会正常返回函数,但 Promise 的不同之处在于您可以在完成后执行操作。

    例子:

    static myActionCreator(somevar) {
      return dispatch => {
        return new Promise((resolve, reject) => {
          dispatch({
            type: "myaction",
            something: somevar
          });
    
          resolve()
        });
      }
    }
    

    所以在这种情况下,您的 thunk 会返回一个承诺。然后当你这样调用时:

    this.props.myActionCreator(somevar)
    .then(() => {
      this.props.history.push('/winning')
    })
    

    这个 thunk 只是调度一个动作,但你可以在那里有一些异步调用,其中有一个回调等,你在完成时解决。

    【讨论】:

    • 我还没有在任何类型的 reac-redux 文档中看到这样的承诺。你确定没有更常见的方式来以这种方式融合react-routerredux
    • @KellysOnTop23 阅读 redux-thunk 文档。他们谈论使用承诺来达到这种效果。 react-redux 处理动作对象,thunk 是作为函数的动作(您可以在其中找到这样的示例)。
    • 关于如何使用 async-await 执行此操作的任何建议?
    • @PeterG Async 和 Await 只是 Promises 的语法糖,所以第一个代码块保持不变。第二个(调用它)变为await this.props.myActionCreator(somevar); this.props.history.push('/winning');
    • 这不起作用。 Promise 不知道 dispatch 是什么。为什么所有的点?
    【解决方案4】:

    我也有类似的困惑,最终花了很多时间通过回调和 javascript 承诺解决问题,因为 react-redux 设置根本不需要。

    this.props.clearReducersState()
    this.props.history.push('/dashboard')
    

    在我的 clearReducerState() 函数被调度后,我试图转到我的仪表板。 这段代码工作得很好。

    你不需要做任何事情 react-redux 以同步方式工作,所以你可以简单地做到这一点。 为此,您也可以在您的操作中使用 history.push,

    import { withRouter } from 'react-router-dom';
    this.props.clearReducersState(this.props.history)
    
    export default connect(mapStateToProps, mapDispatchToProps)(withRouter(UpdateAid))
    

    在你的行动中,

    export const clearReducersState = (history) => dispatch => {
    history.push('/dashboard')
    }
    

    但是,如果您使用 reducer 更新状态,最好在索引文件中使用 history.push 以避免出现问题。

    根据您的要求使用。 希望这会有所帮助。

    【讨论】:

      【解决方案5】:

      我认为您正在寻找的是 Redux Saga

      您可以使用 TakeEvery 效果,每次调用特定操作时都会触发您想要的功能。

      例子:

      import { takeEvery } from `redux-saga/effects`
      
      function* fetchUser(action) {
        ...
      }
      
      function* watchFetchUser() {
        yield takeEvery('USER_REQUESTED', fetchUser)
      }
      

      看看doc 和 阅读此article

      【讨论】:

        【解决方案6】:

        正如official Redux tutorials 所建议的那样,我使用了另一种方法。

        将枚举 status 添加到您的状态,以及变量 error = null

        然后您可以为它们分配各种类型的状态。 你的情况

        status = "idle" | "pending" | "failed" | "loggedin" | "loggedout";
        

        然后在你的 thunk 中,

        if (login succeeds)
           status = 'loggedin';
        else {
            status = 'failed';
            error = 'e.message if you are using try catch';
        }
        

        在您的功能组件中,

        const {status,error} = useSelector(state => ({state.status,state.error}));
        const dispatch = useDispatch();
        useEffect(()=>{
            if(status === "loggedin") 
                 // don't forget to reset the status
                 dispatch(setStatus('idle'));
                 history.push('/dashboard');
            if(status === "failed")
                dispatch(setStatus('idle'));
                console.log(error);
        },[status]);
                
        

        【讨论】:

          猜你喜欢
          • 2021-11-11
          • 1970-01-01
          • 2021-03-05
          • 2017-02-09
          • 1970-01-01
          • 2020-04-26
          • 1970-01-01
          • 2019-04-25
          • 1970-01-01
          相关资源
          最近更新 更多