我正在为我的网站构建随机匹配功能。在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);
It looks you are using redux thunk and as the docs says:
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 exceptionMATCHING_REQUEST
).since
startConversation
is async and you need these dispatches to be executed after its resolution, you should consider callingMATCHING_SUCCESS
andMATCHING_FAIL
atstartConversation
.