按顺序Redux调度动作

我正在为我的网站构建随机匹配功能。在startMatching Redux操作结束时,如果匹配成功,我想在调度MATCHING_SUCCESS之前调度另一个名为startConversation的操作。 startConversation操作用于创建或更新2个用户之间的聊天记录,并将在末尾调度将聊天记录作为有效负载存储的Firestore文档的ID。由于(1)在MATCHING_SUCCESS之前调度了startConversation,并且(2)在startConversation调度了聊天历史文档的ID之前,我可以在Redux状态下创建一个名为chatid的字段,以在匹配成功完成后访问该文档的ID并使用它生成类似聊天窗口的内容。

我一直在测试应该成功完成匹配的情况下的代码。我遇到的问题是,第二个调度(MATCHING_SUCCESS)完成之后,第一个调度(startConversation)已完成。我之所以知道这一点,是因为我将console.log放在MatchingBox组件的componentDidUpdate方法中,并且在startConversation操作的结尾,并且前者中的console.log早于后者执行,这意味着MATCHING_SUCCESS已在startConversation之前完成分派这导致Redux状态发生变化,从而支撑了该组件。实际上,MatchingBox组件状态下的伙伴和加载字段已更新,并且聊天对象仍为空字符串。我不希望发生这种情况,因为如您所见,我需要将chatid进一步传递给MatchingWindow组件。

这让我感到困惑:毕竟,Redux不同步吗?另外,我尝试用“ then”链接两个调度,并且startConversation仍比MATCHING_SUCCESS晚完成调度。我想知道如何解决此问题。非常感谢您的耐心配合!

Redux动作


export const startConversation = (user2id, user2profile, user1profile, message) => (dispatch, getState) => {

  ......

  console.log(chatid);
  dispatch({ type: CHAT_SUCCESS, payload: chatid });

}


export const startMatching = (userid, userprofile, usergender, genderpreference) => (dispatch) => {
    dispatch({ type: MATCHING_REQUEST });

  ...Matching algorithm...

  //Dispatches                      
 firebase.firestore().collection("users").doc(userspool[number].id).get()
     .then((doc) => {
       dispatch(startConversation(userspool[number].id, doc.data(), userprofile, {time: "", from: "", content: ""}));      
       dispatch({ type: MATCHING_SUCCESS, payload: doc.data() });
      })

  if (buddy === "") {
      dispatch({ type: MATCHING_FAIL, payload: [] });
    }

  console.log(buddy);      
}

Redux减速器

const initialState = {

    ......

    loading: false,
    chatid: "",
    buddy: [],
}

const authReducer = (state = initialState, action) => {
    const {type, payload} = action;

    switch(type) {

        ......

        case CHAT_SUCCESS:
            return {
                ...state,
                chatid: action.payload
            }
        case MATCHING_REQUEST:
            return {
                ...state,
                loading: true
            }
        case MATCHING_SUCCESS:
            return {
                ...state,
                buddy: action.payload,
                loading: false
            }
        case MATCHING_FAIL:
            return {
                ...state,
                buddy: action.payload,
                loading: false
            }

        default: return state;
    }
}

MatchingBox组件

class MatchingBox extends Component {

    state = {
        show: true,
        loading: false,
        chatid: "",
        buddy: []
    }

    componentDidMount() {
        this.setState({
            loading: this.props.loading,
        })
    }


    componentDidUpdate(prevprops) {
        console.log(this.props.chatid);
        console.log(this.props.buddy.first_name);
        if (prevprops.loading !== this.props.loading) {
            this.setState({
                loading: this.props.loading,
                chatid: this.props.chatid,
                buddy: this.props.buddy
            })
        }
    }



    render() {

        let box;
        if (this.props.loading === true) {
            box = <span>Loading...</span>
        }
        else {

            if (this.props.buddy.length !== 0) {
                box = <div>
                <div className="form-inline">
                    <img src={this.state.buddy.image}></img>
                    <img src={this.props.profile.image}></img>
                </div>
                <MatchingWindow chatid={this.state.chatid} />
                </div>
            }

            else {
                box = <span>Sorry we cannot help you find a study/work buddy currently</span>
            }
        }
        return (
            <Modal show={this.state.show}>
            <Modal.Header closeButton></Modal.Header>
            <Modal.Body>
              {box}
            </Modal.Body>
          </Modal>
        );
    }

}

const mapStateToProps = (state) => {
    return {
        auth: state.firebase.auth,
        loading: state.auth.loading,
        chatid: state.auth.chatid,
        buddy: state.auth.buddy,
        profile: state.firebase.profile
    };
}

export default connect(mapStateToProps)(MatchingBox);
评论
  • cut
    cut 回复

    It looks you are using redux thunk and as the docs says:

    Redux Thunk中间件允许您编写返回的动作创建者   功能而不是动作。重击可以用来延迟   分派动作,或仅在满足特定条件时分派   遇见。内部函数接收存储方法分派和   getState作为参数。

    your action reducer startConversation does some async action right? in that way redux thunk will hold that dispatch to be executed until its resolution, but wont block the following code from being executed.

    next line MATCHING_SUCCESS is executed right away, it does not wait for the pending previous one to be solved. Likewise, MATCHING_FAIL is outside from the promise and probably is triggered before all dispatches (with exception MATCHING_REQUEST).

    since startConversation is async and you need these dispatches to be executed after its resolution, you should consider calling MATCHING_SUCCESS and MATCHING_FAIL at startConversation.