useEffect内部的状态始终使用React Hooks引用初始状态 [英] state inside useEffect refers the initial state always with React Hooks
问题描述
每次我从另一个组件发出消息时,我都无法获得消息的完整列表.这是钩子和视图组件:
Every time I emit a message from another component, I can't get the full list of messages. Here is the hook and view component:
export function useChat() {
const [messages, setMessages] = useState([]);
useEffect(() => {
const socket = openSocket("http://localhost:3003");
socket.on("chat message", msg => {
const newState = update(messages, { $push: [msg] });
setMessages(newState);
});
}, []);
return { messages };
}
不幸的是,状态不会持久,并且总是显示最后一条消息:
Unfortunately the state doesn't persist and shows always the last message:
export const HookSockets = () => {
const { messages } = useChat();
return (
<div>
{messages.map((message, index) => (
<div key={index}>{message}</div>
))}
</div>
);
};
如果我按常规方式进行操作,那么一切都会按预期进行:
If I do this the regular way, everything works as intended:
export class ClassSockets extends Component {
state = {
socket: openSocket("http://localhost:3003"),
messages: [],
message: ""
};
componentDidMount() {
this.state.socket.on("chat message", msg => {
const newState = update(this.state, {
messages: { $push: [msg] }
});
this.setState(newState);
});
}
handleClick = () => {
this.state.socket.emit("chat message", this.state.message);
this.setState({ message: "" });
};
handleChange = event => {
this.setState({ message: event.target.value });
};
render() {
return (
<div>
<div>Sockets</div>
<div>{this.state.messages}</div>
<input
type="text"
value={this.state.message}
onChange={this.handleChange}
/>
<button onClick={this.handleClick}>Send Message</button>
</div>
);
}
}
推荐答案
由于您编写了useEffect以便在组件的初始安装时执行,因此它会创建一个引用messages
初始值的闭包,即使消息已更新也是如此. ,那么在后续调用中它仍将引用相同的值
Since you have written your useEffect to execute on initial mount of component, it creates a closure which references the initial value of messages
and even if the messages update, it will still refer to the same value on subsequent calls
您应该将useEffect
配置为在初始安装和消息更改时运行
You should instead configure the useEffect
to run on initial mount and messages change
export function useChat() {
const [messages, setMessages] = useState([]);
useEffect(() => {
const socket = openSocket("http://localhost:3003");
socket.on("chat message", msg => {
const newState = update(messages, { $push: [msg] });
setMessages(newState);
});
}, [messages]);
return { messages };
}
否则您可以使用回调模式来更新状态
or else you could use the callback pattern to update state
export function useChat() {
const [messages, setMessages] = useState([]);
useEffect(() => {
const socket = openSocket("http://localhost:3003");
socket.on("chat message", msg => {
setMessages(prevMessages => update(prevMessages, { $push: [msg] }););
});
}, []);
return { messages };
}
这篇关于useEffect内部的状态始终使用React Hooks引用初始状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!