I am building a random matching feature for my website. At the end of the startMatching Redux action, if the matching is successful, I want to dispatch another action called startConversation before dispatching MATCHING_SUCCESS. The startConversation action is used to create or update the chat history between 2 users and will dispatch the id of the firestore document that stores the chat history as the payload at the end. Since (1) startConversation is dispatched before MATCHING_SUCCESS and (2) startConversation dispatches the id of the chat history document, I can create a field called chatid in my Redux state to access the id of the document once the matching is successfully done and use it to generate something like a chat window.
I have been testing the code with a case in which matching should be successfully done. The problem I got was that the first dispatch (startConversation) was completed after the second dispatch (MATCHING_SUCCESS) was completed. I knew this because I put console.log in the componentDidUpdate method of the MatchingBox component and at the end of the startConversation action, and the console.log in the former was executed earlier than the latter, which means that MATCHING_SUCCESS was finished dispatching before startConversation which caused a change in Redux state and thus props to the component. Indeed, the buddy and loading fields in the state of the MatchingBox component were updated and the chatid remained as an empty string. I do not want this to happen because as you can see I need to pass chatid further down to the MatchingWindow component.
This makes me confused: After all, isn't Redux synchronous? Also, I tried chaining the 2 dispatches with "then" and startConversation was still finished dispatching later than MATCHING_SUCCESS. I am wondering how I can fix the issue. Thank you so much for your patience!
Redux actions
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 reducer
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 component
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);