Saltar al contenido

¿Cómo puedo forzar al componente a volver a renderizar con ganchos en React?

Solución:

Esto es posible con useState o useReducer, ya que useState usos useReducer internamente:

const [, updateState] = React.useState();
const forceUpdate = React.useCallback(() => updateState({}), []);

forceUpdate no está diseñado para usarse en circunstancias normales, solo en pruebas u otros casos pendientes. Esta situación se puede abordar de una manera más convencional.

setCount es un ejemplo de mal uso forceUpdate, setState es asíncrono por razones de rendimiento y no se debe forzar a ser síncrono solo porque las actualizaciones de estado no se realizaron correctamente. Si un estado se basa en un estado establecido previamente, esto debe hacerse con la función de actualización,

Si necesita establecer el estado en función del estado anterior, lea sobre el argumento del actualizador a continuación.

<...>

Se garantiza que tanto el estado como los accesorios recibidos por la función de actualización están actualizados. La salida del actualizador se fusiona superficialmente con el estado.

setCount Puede que no sea un ejemplo ilustrativo porque su propósito no está claro, pero este es el caso de la función de actualización:

setCount(){
  this.setState(({count}) => ({ count: count + 1 }));
  this.setState(({count2}) => ({ count2: count + 1 }));
  this.setState(({count}) => ({ count2: count + 1 }));
}

Esto se traduce 1: 1 a ganchos, con la excepción de que las funciones que se utilizan como devoluciones de llamada deben memorizarse mejor:

   const [state, setState] = useState({ count: 0, count2: 100 });

   const setCount = useCallback(() => {
     setState(({count}) => ({ count: count + 1 }));
     setState(({count2}) => ({ count2: count + 1 }));
     setState(({count}) => ({ count2: count + 1 }));
   }, []);

Como han mencionado los demás, useState funciona – así es como mobx-react-lite implementa actualizaciones; podrías hacer algo similar.

Definir un nuevo gancho useForceUpdate

import { useState, useCallback } from 'react'

export function useForceUpdate() {
  const [, setTick] = useState(0);
  const update = useCallback(() => {
    setTick(tick => tick + 1);
  }, [])
  return update;
}

y usarlo en un componente –

const forceUpdate = useForceUpdate();
if (...) {
  forceUpdate(); // force re-render
}

Consulte https://github.com/mobxjs/mobx-react-lite/blob/master/src/utils.ts y https://github.com/mobxjs/mobx-react-lite/blob/master/src/useObserver .ts

Generalmente, puede usar cualquier enfoque de manejo de estado que desee para activar una actualización.

Con TypeScript

ejemplo de codesandbox

useState

const forceUpdate: () => void = React.useState()[1].bind(null, {})  // see NOTE below

useReducer

const forceUpdate = React.useReducer(() => ({}), {})[1] as () => void

como gancho personalizado

Simplemente envuelva el enfoque que prefiera así

function useForceUpdate(): () => void {
  return React.useReducer(() => ({}), {})[1] as () => void // <- paste here
}

¿Cómo funciona esto?

Para activar una actualización significa decirle al motor React que algún valor ha cambiado y que debería volver a entregar su componente.

[, setState] de useState() requiere un parámetro. Nos deshacemos de él atando un objeto nuevo. {}.
() => ({}) en useReducer es un reductor ficticio que devuelve un objeto nuevo cada vez que se envía una acción.
{} (objeto nuevo) es necesario para que active una actualización cambiando una referencia en el estado.

PD: useState solo envuelve useReducer internamente. fuente

NOTA: El uso de .bind con useState provoca un cambio en la referencia de función entre las representaciones. Es posible envolverlo dentro de useCallback como ya se explicó aquí, pero entonces no sería un sexy one-liner ™. La versión Reducer ya mantiene igualdad de referencia entre renders. Esto es importante si desea pasar la función forceUpdate en props.

JS simple

const forceUpdate = React.useState()[1].bind(null, {})  // see NOTE above
const forceUpdate = React.useReducer(() => ({}))[1]
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *