更新到原始帖子:我已经意识到问题是Redux状态(WaitingRoom组件的属性)中的更新以某种方式将组件的整个状态设置为其初始状态。因此,“ showmatchingwindow”也设置为false。最初,在调度MATCHING_REQUEST并将“ loading”设置为true之后,WaitingRoom组件的状态仍保持不变。但是,在调度MATCHING_SUCCESS并将“ loading”设置为false并更新Redux状态下的“ buddy”和“ chatid”之后,处于等待状态的所有字段都将以某种方式重置为其初始值。这很奇怪,我的其他Redux动作都没有发生。我想知道是否有人可以帮助我解释造成这种情况的原因。非常感谢您的耐心配合和提供的任何帮助!
链接到Github存储库:https://github.com/liu550/salon_project(WaitingRoom组件位于src / components / waitingroom.js中
///以下是原始帖子////
我正在为我的网站构建随机匹配功能。 以下是简短说明:我希望在成功匹配2个用户后弹出聊天窗口。在我的Redux状态中,我有(1)“正在加载”,(2)“好友”代表与当前用户匹配的用户ID,以及(3)“ chatid”代表存储的Firestore文档的ID 2位用户之间的聊天记录。在WaitingRoom组件中调用了startMatching Redux操作,该组件是一个网页,除了具有匹配按钮之外,还显示其他用户的配置文件。聊天窗口是MatchingWindow组件,它需要一个聊天对象作为其道具来呈现2个用户之间的相应聊天记录。
我确定我的Redux操作可以正常运行,但是在将更新的Redux状态传递给我的React组件时遇到了问题。以下是我尝试的2种方法:
方法1 :在WaitingRoom组件返回的模式内显示聊天窗口。如您所见,我在这里所做的只是条件渲染。但是,采用这种方法后,该模式很快就会出现不到一秒钟的时间,然后与之前的模式(用户选择自己的性别偏好)一起消失了。检查WaitingRoom组件的道具后,我发现“ buddy”和“ chatid”确实已更新。不应该渲染MatchingWindow吗?我还尝试只放置成功>而不是MatchingWindow组件,结果是一样的。
方法1(等候室)
class WaitingRoom extends Component {
state = {
......
}
showMatching = (e) => {
e.preventDefault();
this.setState({
showmatching: true
})
}
handleMatching = (e) => {
e.preventDefault();
this.props.startMatching(this.props.auth.uid, this.props.profile, this.props.profile.gender, this.state.genderpreference);
this.setState({
showmatchingwindow: true
})
}
closeMatching = () => {
this.setState({
showmatching: false
})
}
render() {
const { auth, users, profile, loading, sent, buddy, chatid } = this.props;
return (
<div>
<Button variant="success" onClick={this.showMatching} style={{ fontSize: "large", fontFamily: "Comic Sans MS, cursive, sans-serif"}}>Randomly find a study/work buddy instantly!</Button>
</div>
<Modal show={this.state.showmatching} onHide={this.closeMatching}>
<Modal.Header closeButton></Modal.Header>
<Modal.Body>
<form onSubmit={this.handleMatching}>
Match me with:
<div className="form-inline">
<div className="radio-container">
<label>Male only</label><input type="radio" id="genderpreference" value="Male" onChange={this.handleChange} checked={this.state.genderpreference === "Male"} />
</div>
......
</div>
<button>Start matching</button>
</form>
</Modal.Body>
</Modal>
<Modal show={this.state.showmatchingwindow} onHide={this.closeMatching}>
<Modal.Header closeButton></Modal.Header>
<Modal.Body>
{ loading ? <div class="loader"></div> : null}
{ buddy !== "" && loading === false ? <MatchingWindow chatid=chatid /> : null }
{ buddy === "" && loading === false ? <span>Sorry we cannot help you find a study/work buddy currently</span> : null }
</Modal.Body>
</Modal>
);
}
}
const mapStateToProps = (state) => {
return {
users: state.firestore.ordered.users,
auth: state.firebase.auth,
profile: state.firebase.profile,
loading: state.auth.loading,
sent: state.auth.sent,
buddy: state.auth.buddy,
chatid: state.auth.chatid
}
}
export default compose(
connect(mapStateToProps, {submitTicket, startMatching, groupMessaging}),
firestoreConnect([
{ collection: 'users' }
])
)(WaitingRoom);
方法2 :创建一个单独的MatchingBox组件,该组件将根据不同的状态呈现不同的元素/组件。但是,当我采用这种方法时,在Redux状态更改后未触发componentWillReceiveProps(),因为未执行放置在该方法内的console.log()。这很奇怪,因为正如我在方法1中提到的那样,当我检查WaitingRoom组件的道具时,确实确实改变了Redux的状态,这意味着我的Redux操作和reducer代码应该很好,并且对于MatchingBox组件应该工作相同也一样由于未触发componentWillReceiveProps(),我传递给MatchingWindow组件的chatid是一个空字符串,这是有问题的。我尝试了componentDidUpdate(),它也不起作用。
方法2(等候室)
class WaitingRoom extends Component {
render() {
return (
......All the same except for replacing the second Modal with:
{ this.state.showmatchingwindow ? <MatchingBox /> : null }
);
}
}
方法2(匹配框)
class MatchingBox extends Component {
state = {
loading: true,
chatid: "",
buddy: []
}
componentDidMount() {
console.log(this.props.loading);
console.log(this.props.chatid);
console.log(this.props.buddy);
this.setState({
loading: this.props.loading,
chatid: this.props.chatid,
buddy: this.props.buddy
})
}
componentWillReceiveProps() {
console.log(this.props.chatid);
console.log(this.props.buddy);
this.setState({
loading: this.props.loading,
chatid: this.props.chatid,
buddy: this.props.buddy
})
}
render() {
let box;
if (this.props.loading === true) {
box = <div class="loader"></div>
}
else {
if (this.props.buddy !== "") {
box = <div>
<MatchingWindow chatid={this.state.chatid} />
</div>
}
else {
box = <span>Sorry</span>
}
}
return (
<div>
{box}
</div>
);
}
}
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);
如上所述,我很确定我的redux动作和reducer很好,但是只是想让我的描述更容易理解。
Redux操作
export const startMatching = (userid, userprofile, usergender, genderpreference) => (dispatch) => {
dispatch({ type: MATCHING_REQUEST });
......
dispatch(matchingConversation(userspool[number].id, doc.data(), userprofile, {time: "", from: "", content: ""}, number, userspool));
}
export const matchingConversation = (user2id, user2profile, user1profile, message, number, userspool) => (dispatch, getState) => {
.....
.then(() => {
dispatch({ type: CHAT_SUCCESS, payload: doc.id });
})
.then(() => {
dispatch({ type: MATCHING_SUCCESS, payload: user2id });
})
}
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;
}
}
答案 0 :(得分:0)
首先,我认为您不需要在这里使用任何内部状态。当您知道多个组件必须共享相同的变量,并且它们不是分层的时,只需使用存储并使用应用程序状态即可。
第二,我认为在您的化简器中,您可能指向相同的初始状态并直接对其进行突变(违反redux规则)。简而言之,由于复制浅,您的状态可能指向同一旧的初始状态对象,因此您的react组件未检测到更改。
在返回新状态之前,请尝试在redux reducer中创建初始状态的深层副本(而非浅层副本)。这些链接讨论了这些概念:
最后,您的伙伴在初始状态下是否应该是一个空数组而不是字符串?
答案 1 :(得分:0)
您似乎正在使用函数来返回组件:
// main.js
const WaitingRoomPage = () => {
return <WaitingRoom />;
};
...
<Route path='/waitingroom' component={WaitingRoomPage} />
我认为您不应该这样做,因为每次重新渲染Main都会导致您的WaitingRoom
保留remounting (and thus re-initializing)。您的WaitingRoom
不是功能组件,即使是,也应该使用更简单的方法来声明带有Route
属性的component
:
<Route path='/waitingroom' component={WaitingRoom} />