【问题标题】:Passing websocket ref to child component将 websocket ref 传递给子组件
【发布时间】:2021-05-28 01:44:24
【问题描述】:

我已经在父组件中建立了一个 websocket 连接,并使用 useRef 将其存储在变量 socket 中。现在,我将这个socket 传递给道具中的子组件。我想在子组件中使用这个套接字来发出组件特定的事件,并根据一些 websocket 事件更新特定于组件的某些状态变量。

父组件

function Parent(props) {
  const userId = props.userId;
  const socket = useRef(null);

  useEffect(() => {
    if (userId) {
      socket.current = services.establishSocketConnect(userId);
    }
    return () => {
      socket.current.close();
    };
  }, []);

  return (
    <React.Fragment>
      <Child socket={socket} />
    </React.Fragment>
  );
}

const mapStateToProps = (state) => ({
  userId:
    (state.userInfo && state.userInfo.user && state.userInfo.user._id) || null,
});

export default connect(mapStateToProps, null)(Parent);

子组件

function Child(props) {
  const { socket } = props;

  useEffect(() => {
    console.log('Child => socket', socket);
    if (socket.current) {
      console.log('attaching socket events');
    }
  }, []);

  return <h1>Child</h1>;
}

const mapStateToProps = (state, otherProps) => {
  return {
    // ...
    ...otherProps,
  };
};

export default connect(mapStateToProps, null)(Child);

在子组件中,socket.current 没有 websocket 连接。我知道在初始渲染时,该值将为空。所以,这就是 Child 组件最初收到的内容。因此,我尝试将socketsocket.current 添加到useEffect,以便子组件在更改时重新渲染。但是,这不会发生,因为可变对象不能用作 useEffect 的依赖项,我猜..

请提出解决此问题的方法。


使用 Robin Zigmond's solution 和一些额外的日志记录。

家长

function Parent(props) {
  const userId = props.userId;
  const socket = useRef(null);

  useEffect(() => {
    console.log('Parent => (initial) socket', socket);

    socket.current = services.establishSocketConnection(userId);

    if (socket.current) {
      socket.current.onopen = onWSOpenEvent();
    }

    let i = setInterval(() => console.log('Parent => (interval) socket', socket), 5000);

    return () => {
      clearInterval(i);
    };
  }, [userId]);

  return (
    <React.Fragment>
      <Child socket={socket.current} />
    </React.Fragment>
  );
}

儿童

function Child(props) {
  const { socket } = props;

  useEffect(() => {
    console.log('Child => (initial) socket', socket);
    if (socket) {
      console.log('attaching socket events');
    }

    let i = setInterval(() => console.log('Child => (interval) socket', socket), 5000);

    return () => {
      clearInterval(i);
    };
  }, [socket]);

  return <h1>Child</h1>;
}

这不起作用。以下是日志:

【问题讨论】:

    标签: javascript reactjs sockets websocket


    【解决方案1】:

    问题是您将 socket 作为 prop 传递给子组件 - 按照设计,它是一个可变对象,其 current 属性发生更改,同时保持整个对象的相同引用。但是当你将整个对象传递给子组件时,这与 React 道具并不能很好地配合——因为当 current 属性发生变化时,React 不会“看到”这种变化(道具仍然和以前一样before - 对同一对象的引用),因此它不会重新渲染子对象。

    解决方案非常简单——不要将可变对象作为道具传递,而只是传递您关心的current 属性:

    <Child socket={socket.current} />
    

    现在,当您在 Child 组件中引用 socket 属性时,它应该具有实际的 websocket 连接。

    编辑:如果要在子组件中记录当前套接字值,每次更改时,子组件中的useEffect 应该是

    useEffect(() => {
        console.log('Child => socket', socket);
        if (socket) {
          console.log('attaching socket events');
        }
    }, [socket]);
    

    【讨论】:

    • 问题不在 Parent 组件中。在 Parent 的第一次挂载中,userId 是一个有效字符串。因此,websocket 正在 Parent 中正确建立。实际问题出在 Child 组件中,我没有在socket.current 变量中接收到套接字连接。
    • 哦,我明白了,抱歉,我没有意识到这一点 - 特别是当您谈到尝试将 socket 添加为 useEffect 的依赖项时。我现在看到了真正的问题(这是因为您正在改变通过 ref 传递给子组件的道具)。我将使用(我现在认为的)正确的解决方案进行编辑!
    • 我已经尝试过了,但它不起作用。仍然在 Child 组件中接收 null 作为 socket。我已经在 Child 中尝试了 useEffect ,它依赖于 socket 但即使这样也没有帮助。
    • 谢谢,我忽略了孩子也是不正确的。我已经添加了那里需要的更改 - 听起来你已经尝试过这个,但它不会伤害明确。如果这不起作用,那么在不知道究竟记录了什么以及记录了多少次的情况下,我将无能为力。
    • 我已经尝试了您在问题中更新的解决方案。在 Child 中接收 socket 为 null。请检查
    猜你喜欢
    • 2017-08-16
    • 2021-03-14
    • 2021-06-04
    • 2022-12-18
    • 2017-12-02
    • 2017-12-26
    • 2020-01-14
    • 2019-04-12
    • 1970-01-01
    相关资源
    最近更新 更多