我正在使用Reactjs和Redux构建一个聊天应用程序。我有两个名为ChatHeads和ChatBox的组件,它们同时并排安装。
在ChatHeads组件中,可以选择User(您想与之聊天的对象),此选择存储在Redux存储中,作为chatInfo
。
ChatHeads组件:
function ChatHeads(props) {
const {
dispatch,
userInfo,
userId
} = props;
const [chatHeads, setChatHeads] = useState([]);
const handleChatHeadSelect = (chatHead, newChat = false) => {
dispatch(
chatActions.selectChat({
isNewChat: newChat,
chatId: chatHead.chat._id,
chatUser: chatHead.user
})
);
};
const loadChatHeads = async () => {
const response = await services.getRecentChats(userId, userInfo);
setChatHeads(response.chats);
};
useEffect(() => loadChatHeads(), [userInfo]);
return (
// LOOPING THOUGH ChatHeads AND RENDERING EACH ITEM
// ON SELECT OF AN ITEM, handleChatHeadSelect WILL BE CALLED
);
}
export default connect(
(state) => {
return {
userInfo: state.userInfo,
userId: (state.userInfo && state.userInfo.user && state.userInfo.user._id) || null,
selectedChat: (state.chatInfo && state.chatInfo.chat && state.chatInfo.chat._id) || null
};
},
null,
)(ChatHeads);
字符串
聊天操作和还原器:
const initialState = {
isNewChat: false,
chatId: '',
chatUser: {},
};
const chatReducer = (state = initialState, action) => {
let newState;
switch (action.type) {
case actions.CHAT_SELECT:
newState = { ...action.payload };
break;
default:
newState = state;
break;
}
return newState;
};
export const selectChat = (payload) => ({
type: actions.CHAT_SELECT,
payload,
});
型
在ChatBox组件中,我正在建立一个到服务器的套接字连接,并基于全局存储中的chatInfo
对象& ws事件,执行一些操作。
聊天框组件:
let socket;
function ChatBox(props) {
const { chatInfo } = props;
const onWSMessageEvent = (event) => {
console.log('onWSMessageEvent => chatInfo', chatInfo);
// handling event
};
useEffect(() => {
socket = services.establishSocketConnection(userId);
socket.addEventListener('message', onWSMessageEvent);
return () => {
socket.close();
};
}, []);
return (
// IF selectedChatId
// THEN RENDER CHAT
// ELSE
// BLANK SCREEN
);
}
export default connect((state) => {
return {
chatInfo: state.chatInfo
};
}, null)(ChatBox);
型
步骤:
1.渲染完两个组件后,我在ChatHeads组件中选择一个用户。
1.使用Redux DevTools,我能够观察到chatInfo
对象已经正确填充。
chatInfo: {
isNewChat: false,
chatId: '603326f141ee33ee7cac02f4',
chatUser: {
_id: '602a9e589abf272613f36925',
email: '[email protected]',
firstName: 'user',
lastName: '2',
createdOn: '2021-02-15T16:16:24.100Z',
updatedOn: '2021-02-15T16:16:24.100Z'
}
}
型
1.现在,每当在ChatBox组件中触发'message'事件时,我的期望是chatInfo
属性应该具有最新的值。但是,我总是得到initialState而不是更新的值。
chatInfo: {
isNewChat: false,
chatId: '',
chatUser: {}
}
型
我错过了什么?请建议...
2条答案
按热度按时间tvokkenx1#
这种行为的原因是,当您声明回调时,
字符串
它会记住在声明的这个时刻(这是初始呈现)
chatInfo
是正确的。对于回调来说,值在store和组件呈现作用域内被更新并不重要,重要的是回调作用域以及当你声明回调时chatInfo
引用的是什么。如果你想创建一个总是可以读取最新状态/属性的回调函数,你可以将
chatInfo
保存在一个可变引用中。型
您可以检查this codesandbox以查看使用ref和直接使用prop之间的区别。
你可以参考文档中关于过时的props和useRef文档
一般来说,问题在于您试图在一个范围更窄的组件中管理全局订阅(套接字连接)。
另一个没有
useRef
的解决方案如下所示:型
在这种情况下,消息事件处理程序通过参数传递必要的信息,每次我们得到一个新的
chatInfo
时,useEffect
钩子都会重新运行。但是,这可能与您的目标不一致,除非您希望为每个聊天打开单独的套接字,并在每次切换到不同的聊天时关闭套接字。
因此,“正确的”解决方案需要在项目中将套接字交互上移。一个提示是,您正在使用
userId
打开套接字,这意味着它应该在您知道userId
后运行,而不是在用户选择聊天时运行。要向上移动交互,您可以将传入的消息存储在redux存储中,并通过props将消息传递到
ChatBox
组件。或者您可以在ChatHeads
组件中创建connect to socket,并将消息向下传递到ChatBox
。型
或者你可以创建一个reducer并分派一个
chatActions.newMessage
事件,然后使用redux将消息发送到当前聊天。主要的一点是,如果你需要
chatInfo
来打开套接字,那么每次chatInfo
改变时,你可能都要打开一个新的套接字,所以把依赖项添加到useEffect
钩子上是有意义的。如果它只依赖于userId
,那么把它移到你得到userId
的地方,并连接到那里的套接字。w3nuxt5m2#
使用
store.getState()
获取最新状态我有同样的问题,我在redux存储中有最新的值,但在socket中获得以前的/陈旧的值
以上有参考的回答对我不起作用
所以我使用
store.getState()
来获取当前/最新的状态;字符串