reactjs - useEffect 中的状态总是指 React Hooks 的初始状态

标签 reactjs websocket socket.io immutability react-hooks

每次我从另一个组件发出消息时,我都无法获取完整的消息列表。这是钩子(Hook)和 View 组件:

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 };
}

不幸的是,该状态不会持续存在,并且始终显示最后一条消息:

export const HookSockets = () => {
  const { messages } = useChat();
  return (
    <div>
      {messages.map((message, index) => (
        <div key={index}>{message}</div>
      ))}
    </div>
  );
};

如果我按照常规方式执行此操作,一切都会按预期进行:

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 初始值的闭包,即使消息更新,它仍然会引用相同的值在后续调用中

您应该将 useEffect 配置为在初始安装和消息更改时运行

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 };
} 

否则你可以使用回调模式来更新状态

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 };
}

关于reactjs - useEffect 中的状态总是指 React Hooks 的初始状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54675523/

相关文章:

javascript - 如何使用 ReactJs 对 Cloud Firestore 数据进行分页

grails - 在 Spring Security SavedRequest 中忽略 WebSocket 连接

javascript - STOMP Web 套接字回调不起作用

asp.net - 实时应用程序 - asp.net 替代 node.js 和 socket.io

javascript - 为什么我的 React 组件没有渲染?

node.js - React 路由器、nginx、 Node 、静态文件

javascript - 异步设置 ReactJS 状态

javascript - python websocket 握手 (RFC 6455)

javascript - Python socket.io ack函数

php - Node Socket.io 链接如何在服务器而不是 localhost(wamp/xampp) 中提供