React Hooks – Cómo usar useState o useEffect sin afectar la suscripción.
Estoy tratando de recibir datos de una URL de websocket utilizando la biblioteca web3. Sin embargo, React Hooks me frustra porque vuelve a renderizar toda la función App al actualizar mi array utilizando la función set de useState. ¿Cómo puedo separar mi función de renderizado de la suscripción al websocket? No quiero volver a suscribirme cada vez que use setState.
Aquí está mi código:
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>
);
}
davy.ai
Hay dos enfoques principales para abordar este problema:
1. Evitar las actualizaciones de setState dentro de la suscripción
Una forma de separar la función de renderizado de la suscripción al WebSocket es evitar actualizar directamente la matriz
blocks
consetBlock([...blocks, block.number])
dentro de la suscripción. En cambio, puedes usarsetBlock(blocks => [...blocks, block.number])
para asegurarte de que siempre estás usando el valor más reciente de la matrizblocks
del estado. De esta manera, la suscripción no desencadenará una nueva renderización del componente y podrás evitar volver a suscribirte cada vez que usessetState
.Aquí tienes el código actualizado con este enfoque:
2. Usar un componente separado para la suscripción
Otro enfoque consiste en extraer la lógica de suscripción en un componente separado, que manejaría la conexión WebSocket y las actualizaciones de datos. De esta manera, el componente de suscripción puede encargarse de actualizar su propio estado y pasar los datos al componente padre (
App
), que luego puede renderizar los datos sin desencadenar renderizaciones innecesarias.Aquí tienes un ejemplo de implementación de dicho componente de suscripción:
En este caso,
Subscription
acepta laurl
del WebSocket como una prop y una función de devolución de llamadaonBlockNumberChange
, que se llamará cada vez que cambie el número de bloque. El componente configura la suscripción al WebSocket en su propiouseEffect
y actualiza su propio estadoblockNumber
. CuandoblockNumber
cambia, llama a la función de devolución de llamadaonBlockNumberChange
con el valor más reciente.Ahora, el componente
App
puede renderizar el componenteSubscription
y pasar una función de devolución de llamada para recibir las actualizaciones del número de bloque. También puede usaruseMemo
para evitar renderizaciones innecesarias cuando cambia la matrizblocks
:Este enfoque separa la lógica de suscripción de la lógica de renderizado y evita desencadenar renderizaciones innecesarias al recibir actualizaciones de datos. También permite que el componente de suscripción administre su propio estado y recursos, y hace que el código sea más modular y reutilizable.