es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Flujo de escritura HOC de React (sin HOC)

Necesito escribir HOC para mi componente (y eso se preguntó millones de veces). Pero necesito hacer algo opuesto a lo típico con la inyección withSomething. Necesito agregar una propiedad adicional a mi componente externo y pasar todas las demás propiedades (desconocidas) al componente interno:

// @flow

import * as React from 'react'

// Esto es un ejemplo de un componente estándar que no hace nada
type Props = {|  str: string,  num: number |}
const Hello = ({ str, num }: Props): React.Node => {
  console.log(str, num)
  return <div>'Hello'</div>
}

// Este es el ejemplo estándar (y funcionando) del componente con la propiedad inyectada.
// Es equivalente a la currificación de prop, establezco la propiedad str en un valor predeterminado
type InnerInjected = {| str: string |}
const withInnerInject = <p>(
  Component: React.AbstractComponent<$Exact<{ ...P, ...InnerInjected }>>,
): React.AbstractComponent<p> => {
  return (props: P) => {
    return <component str="aaa" {...props}=""></component>
  }
}

const InnerInjectHello = withInnerInject(Hello)

// Y aquí está el ejemplo que no funciona.
export const withOuterInject = <p>(
  Component: React.AbstractComponent<p>,
): React.AbstractComponent<p> => {
  return (props: P) => {
    // Necesito pasar el bool (u otra variable) a mi componente para realizar alguna acción basada en su valor y devolver el componente estándar con todas las propiedades de ese componente que aún no conozco.
    const { bool, ...rest } = props
    return <component {...rest}=""></component>
  }
}

const OuterInjectHello = withOuterInject(Hello)

const Example = (): React.Node => {
  return (
    <>
      {/* Ambas propiedades num y str se establecen como se desea */}
      <hello num="{25}" str="algo">
      {/* str se inyecta con el valor 'aaa' */}
      <innerinjecthello num="{25}"></innerinjecthello>
      {/* Funciona, pero la escritura es incorrecta */}
      <outerinjecthello str="aa" num="{25}" bool=""></outerinjecthello>

  )
}

He probado varias aproximaciones con $Diff<> y $Rest<>, pero simplemente no funcionan con los genéricos.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Para agregar una propiedad adicional al componente externo mientras se pasan todas las demás propiedades desconocidas al componente interno, puedes usar el tipo de utilidad Omit de TypeScript y el operador de propagación. Aquí tienes un ejemplo de implementación:

    import * as React from 'react';
    
    type PropiedadesInyectadas = {
      foo: string;
    };
    
    type Propiedades = {
      bar: number;
    } & PropiedadesInyectadas;
    
    const ComponenteInterno = (props: Propiedades) => {
      // Haz algo con props.foo y props.bar
      return <div>Hola</div>;
    };
    
    const withPropiedadInyectada = <p extends="" propiedadesinyectadas="">(
      ComponenteInyectado: React.ComponentType,
    ) =>
      function<><p,></p,><keyof p,="" keyof="" propiedadesinyectadas="">>>(ComponenteEnvolvente: React.ComponentType<><p,></p,><keyof p,="" keyof="" propiedadesinyectadas="">>>) {
        const Envoltorio = ({ ...props }: P) => {
          return (
            <componenteinyectado foo="foo">
              <componenteenvolvente {...props="" as=""></componenteenvolvente><p,></p,><keyof p,="" keyof="" propiedadesinyectadas="">>} />
            </keyof></componenteinyectado>
          );
        };
        return Envoltorio;
      };
    
    const ComponenteExterno = withPropiedadInyectada(React.Fragment)(ComponenteInterno);
    
    const Aplicacion = () => {
      return (
        <>
          <componenteinterno foo="foo" bar="{10}"></componenteinterno>
          <componenteexterno foo="foo" bar="{10}"></componenteexterno>
    
      );
    };
    

    En este ejemplo, withPropiedadInyectada es un Componente de Orden Superior que toma un componente inyectado (ComponenteInyectado) y devuelve un nuevo componente (Envoltorio) que envuelve al componente original (ComponenteEnvolvente). El componente Envoltorio recibe todas las propiedades y utiliza el ComponenteInyectado para agregar la propiedad inyectada (foo) a la jerarquía del componente. El ComponenteEnvolvente recibe todas las propiedades desconocidas (es decir, todas las propiedades excepto foo), que se seleccionan utilizando el tipo de utilidad Pick y el tipo de utilidad Exclude. La conversión as Pick<p,></p,><keyof p,="" keyof="" propiedadesinyectadas="">> es necesaria para ayudar a TypeScript a comprender que solo nos interesan las propiedades restantes que no se hayan proporcionado previamente por el ComponenteInyectado.

    Finalmente, se utiliza withPropiedadInyectada con React.Fragment como componente inyectado y ComponenteInterno como componente envuelto para crear ComponenteExterno, que tiene la propiedad foo agregada transmitida por React.Fragment y todas las demás propiedades transmitidas a ComponenteInterno.

    Ten en cuenta que esta implementación utiliza TypeScript en lugar de Flow, pero el concepto debería ser similar. TypeError: get_notifier no es una función

Comments are closed.