我正在通过socket.io
接收消息,并且正在useEffect
钩子函数中侦听传入的消息。
问题是当我更新消息时,它没有成功更新。
export const GroupContext = React.createContext({});
function GroupProvider(props){
const socket = useMemo(()=> io(url), [socket]);
const [messages, setMessages] = useState({});
const setMessage = (message, room) => {
if (messages[room] !== undefined){
setMessages({ [room]: [message, ...messages[room]] });
}
else{
setMessages({ [room]: [message] }); // updating messages per room
}
console.log('room: ', room); // I get the value: roomid100
console.log('message: ', message); // I get the message: Hi dear, How are you
}
useEffect(() => {
console.log('messages: ', messages); // But here I always get the last messages came.
},[messages]);
return (
<GroupContext.Provider value={{socket, messages, setMessage}}>
{props.children}
</GroupContext.Provider>
);
}
function Group(props){
const { socket, messages, setMessage } = useContext(GroupContext);
const receiveMessages = ()=> {
socket.on('getmessage', data => {
setMessage(data.message, data.room);
});
}
useEffect(()=> {
if(socket.connected === true){
receiveMessages();
}else{
socket.connect();
setTimeout(() => {
receiveMessages();
}, 2000);
}
return ()=> unmoun();
}, []);
// ....
}
function Main(){
// ....
return (
<GroupProvider>
<Group />
</GroupProvider>
);
}
注意: 同样的代码在类组件中也可以使用,而无需使用钩子。
在您的示例中,您有两件事: 1( setTimeout 为你的messages
变量做一个闭包(这就是为什么你看到{}
( 2( 使用setMessages({a: 1})
时,会从状态中删除所有其他字段messages
因此,您的代码将按下一个顺序执行(突出显示问题的代码(:
function GroupProvider(props){
const socket = useMemo(()=> io(url), [socket]);
const [messages, setMessages] = useState({});
const setMessage = (message, room) => {
// message = Hi dear, How are you, room: roomid100
// messages: {}
if (messages[room] !== undefined){
setMessages({ [room]: [message, ...messages[room]] });
}
else{
// Problem 1: Here you remove all other changes from you state
setMessages({ [room]: [message] }); // updating messages per room
}
// Problem 2: Here you have a closure to your `messages` variable, so that it will be {}
console.log('room: ', room); // I get the value: roomid100
console.log('message: ', message); // I get the message: Hi dear, How are you
setTimeout(() => {
console.log('messages: ', messages); // But here always I get empty {}
}, 2000);
}
return (
<GroupContext.Provider value={{socket, messages, setMessage}}>
{props.children}
</GroupContext.Provider>
);
}
因此,您可以使用 useEffect 修复它,以便以正确的方式检查变量。我建议你使用setMessages
作为一个函数来简化你的代码:
function GroupProvider(props) {
const socket = useMemo(() => io(url), [socket]);
const [messages, setMessages] = useState({});
const setMessage = (message, room) => {
setMessages((messages) => {
if (messages[room] !== undefined) {
return { ...messages, [room]: [message, ...messages[room]] };
}
return { ...messages, [room]: [message] };
});
};
// we will console log, when `messages` state changes
useEffect(
() => {
console.log('messages: ', messages);
},
[messages]
);
return <GroupContext.Provider value={{ socket, messages, setMessage }}>{props.children}</GroupContext.Provider>;
}