React Hooks - 如何在不影响订阅的情况下使用 useState 或 useEffect?

React Hooks - How to useState or useEffect without affecting subscription?

我正在尝试使用 web3 库从 websocket url 接收数据。然而,React Hooks 让我感到沮丧,因为它在使用 useState set 函数更新我的数组时重新呈现整个 App 函数。如何将渲染函数与 websocket 订阅分开?我不想在使用 setState 时每次都重新订阅。

这是我的代码:

function App() {

console.log('init');
const [blocks, setBlock] = useState([]);

(async () => {
const web3 = new Web3(new

  Web3.providers.WebsocketProvider('wss...'));

web3.eth.subscribe('newBlockHeaders', async (error, blockHeader) => {

  const block = await web3.eth.getBlock(blockHeader.hash, true);

  setBlock([...blocks, block.number]);
  console.log(blocks);

});
})();


return ( 
<div className = "App">
  <header className = "App-header">
    <p>{ blocks }</p>
  </header> 
</div>
);
}

我认为你应该使用 useCallbackuseEffect

const subscribe = useCallback(async () => {
    const web3 = new Web3(new Web3.providers.WebsocketProvider('wss...'));

    web3.eth.subscribe('newBlockHeaders', async (error, blockHeader) => {

        const block = await web3.eth.getBlock(blockHeader.hash, true);

        setBlock([...blocks, block.number]);
        console.log(blocks);

    });
}, [])

useEffect(() => {
    subscribe()
}, [])

使用安装 useEffect 挂钩(即 w/empty 依赖数组)来处理订阅。 Return 取消订阅的清理功能。 useEffect 挂钩运行 一次 来设置订阅,当组件 卸载时 调用清理函数取消订阅

使用功能状态更新将新块编号添加到 blocks 状态。当设置订阅的 newBlockHeaders 事件侦听器回调时,功能状态更新避免了 blocks 状态值的陈旧封闭,它传递先前的状态以进行更新。

useEffect

useState functional updates

function App() {
  const [blocks, setBlock] = useState([]);

  useEffect(() => {
    const web3 = new Web3(new Web3.providers.WebsocketProvider('wss...'));

    const sub = web3.eth.subscribe(
      'newBlockHeaders',
      async (error, blockHeader) => {
        const block = await web3.eth.getBlock(blockHeader.hash, true);
        setBlock(blocks => [...blocks, block.number]);
      },
    );

    return () => sub.unsubscribe();
  }, []);

  return ( 
    <div className = "App">
      <header className = "App-header">
        <p>{ blocks }</p>
      </header> 
    </div>
  );
}