【问题标题】:React + Redux: proper way to handle after-dispatch logicReact + Redux:处理调度后逻辑的正确方法
【发布时间】:2020-02-21 04:20:30
【问题描述】:

我有一个具有某些内部状态(例如 isLoading)的组件,它可以访问 redux 数据。在这个组件中,我想分派一个 thunk 操作(api 请求)导致 redux 数据更改。 thunk 完成后,我需要更改组件的状态。在我看来,有两种方法可以做到这一点:

  1. 使用 thunk 的承诺返回并在那里做我需要的一切,例如
handleSaveClick = (id) => {
    const { onSave } = this.props;
    this.setState({ isLoading: true });
    onSave(id).then(() => this.setState({ isLoading: false }));
};
  1. 将回调传递给 thunk 并从 thunk 本身触发它,例如
  handleSaveClick = (id) => {
    const { onSave } = this.props;
    this.setState({ isLoading: true });
    onSave(id, this.onSaveSuccess);
  };

哪种方法是正确的?

【问题讨论】:

    标签: reactjs redux


    【解决方案1】:

    更安全的方法是使用 Promise 实现,因为您会确定该函数只会在 Promise 解决后运行。第二种实现没有固有缺陷,但是如果您的 thunk 中的任何内容是异步的,那么它将无法正常工作,因为它会在到达代码后运行,而不是在上面的代码完成执行时运行。在处理任何可能异步的事情(服务器请求/加载数据/提交数据)时,使用 Promise 实现总是更安全。

    【讨论】:

    • 关于第一种使用promise的问题:即使promise已经实现了,redux状态还没有被分发到组件是不是还有风险?
    • 不幸的是,我认为您永远无法保证您的组件将首先获得更新的 redux 状态。我假设一旦分派的动作完成,承诺就会被解决,因此已解决的函数将在你的组件中更新 redux 状态之前运行。它还取决于解析函数中的代码,因为 JS 是异步的。如果你确实需要确保在 Redux 状态改变后运行某些东西,你可以使用 componentDidUpdate(prevProps) 来比较 prevProps 和 this.props,然后采取相应的行动。
    • 这也不重要,因为正如另一位评论者所说,一旦 Redux 状态更新,connect 就会触发组件的重新渲染。这实际上取决于您要实现的目标,您是在操作分派后、Redux 状态更改后还是在您的组件获得更新的 Redux 值后尝试执行代码?第一个是通过 thunk 中的 promise 完成的,第三个是通过 componentDidUpdate 完成的。第二个无关紧要,因为 Redux 状态与您的组件是分开的,只要它更新,您就不需要关心它。
    • 好吧,我就是这么想的
    【解决方案2】:

    更新组件级别状态或基于更改 redux 状态(或任何道具/状态更改)运行回调函数的最佳实践可能是使用 componentDidUpdate 或 useEffect:

    componentDidUpdate(prevProps, prevState){
         if(prevProps.someReduxState !== this.props.someReduxState && this.state.isLoading){
            setState({isLoading:false})
         }
    }
    

    使用useEffect:

    useEffect(()=>{
        if(!props.someReduxState){
             setLoading(true)
        } else {
             setLoading(false)
        }
    },[props.someReduxState])
    

    但是,我可能会推荐一种不同的方法(取决于目标,尤其是初始数据获取)来管理 redux 中的状态加载:

    用加载值初始化你的 redux 状态:

    export default someReduxState = (state = {notLoaded:true}, action) => {
        switch (action.type) {
            case actions.FETCH_SOME_REDUX_STATE:
                return action.payload;
            default:
                return state;
        }
    }
    

    然后在你的组件中你可以检查:

    if (this.props.someReduxState.notLoaded ){
        // do something or return loading components
    } else {
        // do something else or return loaded components
    }
    

    【讨论】:

    • 这看起来更像是最坏的做法。如果 state 存储在 redux 中,则在 redux 中处理它。它已经通过connect 触发了重新渲染,所以使用componentDidUpdatethere 实际上是可怕的和不必要的。
    • 我同意这就是为什么我将管理负载状态的“不同方法”放在 redux 中,而不是将 isLoaded 添加到组件级别状态。但是,如果 OP 希望根据 redux 中的某些状态来管理某些组件状态,那么我认为我的答案仍然有效
    • 我编辑了我的答案,以便更清楚地了解最佳实践的含义
    • 我认为在 Redux 中添加或跟踪加载是不可行的,使用本地状态管理它要容易得多。 Redux 状态更新和重新渲染触发之间的时间几乎可以忽略不计。
    • 我同意在组件级别管理加载状态很有用。答案的后半部分有助于在最初获取和调度数据时避免不必要的渲染。通过使用诸如{notLoaded:true}之类的加载值进行初始化来管理加载状态(如果需要再次重新加载数据,也可以在卸载时重置为该值)
    猜你喜欢
    • 1970-01-01
    • 2016-10-12
    • 1970-01-01
    • 2019-10-20
    • 1970-01-01
    • 2020-10-28
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多