我正在尝试使用web3库从websocket url接收数据。然而,React Hooks让我很沮丧,因为它在使用useState set函数更新数组时重新渲染了整个应用程序函数。如何将渲染函数与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>
);
}
使用挂载useEffect
挂钩(,即w/empty依赖数组(来处理订阅。返回一个清除函数以取消订阅。useEffect
挂钩运行一次以设置订阅,当组件卸载时调用清除函数以取消订阅。
使用功能状态更新将新的块号添加到blocks
状态。当设置订阅的newBlockHeaders
事件侦听器回调时,功能状态更新避免了blocks
状态值的陈旧外壳,它会传递到以前的状态中进行更新。
useEffect
useState
功能更新
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>
);
}
我认为您应该使用useCallback
和useEffect
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()
}, [])