Llamar a un gancho de React condicionalmente

Resuelto Sheraff asked hace 3 años • 3 respuestas

De la documentación oficial de React sabemos que "React depende del orden en que se llaman los Hooks" . Entonces, ¿hay algo de malo en "reservar" un lugar para un gancho si quiero llamarlo condicionalmente?

function Component({flag, depA, depB}) {

  if (flag) {
    // just "reserving a spot"
    useEffect(() => {}, [null, null])
  } else {
    useEffect(() => {
      // ... actual hook
    }, [depA, depB])
  }

  return <></>
}

Si esto funciona, ¿funcionaría también para useCallback? useLayoutEffect? useMemo?useImperativeHandle?

Probé todo esto y, en contextos mucho más complicados, parece funcionar aunque el linter se queja. ¿Me estoy perdiendo de algo?

PD: si parece un poco inútil así, es porque el objetivo final es que la parte principal del gancho se cargue de forma diferida import()y, antes de que se active y resuelva la importación, simplemente reserve los lugares para los ganchos.

Sheraff avatar Jun 04 '21 02:06 Sheraff
Aceptado

Justo estaba pensando en esto hoy. Creo que si bien "rompe las reglas", React no puede hacer nada para notar la diferencia entre los dos.

Entonces, aunque se infrinjan las reglas, si se tiene una razón suficientemente buena y se comprenden los riesgos, entonces las "reglas" son sólo dogmas.

React básicamente sabe qué gancho useEffect es cuál, al contar las invocaciones. Llamar useEffectcondicionalmente es malo, específicamente porque la cantidad de veces useEffectque se llama no puede cambiar.

Su ejemplo es condicional, pero React no puede detectarlo porque en cualquiera de las condiciones lo llama una vez.

Sin embargo, el ejemplo que mencionas parece que no necesita esto. Hay buenas razones para hacer las cosas de la manera "normal", porque como puedes ver por otros comentaristas aquí, causa confusión y sorpresa, y no nos gusta la sorpresa =)

Si está cargando alguna funcionalidad de forma diferida, simplemente haga que su useEffectgancho llame a la función cuando esté lista .

Evert avatar Jun 05 '2021 03:06 Evert

Mi solución es así y funciona para todos los ganchos, sin embargo es mejor usarla cuando sea necesario ya que puede causar confusión y sorpresa.

const ConditionalEffect1 = () => {
  useEffect(() => {}, [])
  return null
}

const ConditionalEffect2 = ({depA, depB}) => {
  useEffect(() => {}, [depA, depB])
  return null
}

const Component = ({ flag, depA, depB }) => {
  return flag 
          ? <ConditionalEffect1 /> 
          : <ConditionalEffect2 depA={depA} depB={depB} />
}

Hamid Shoja avatar Aug 11 '2022 12:08 Hamid Shoja