Cómo pasar accesorios a {this.props.children}

9 minutos de lectura

Como pasar accesorios a thispropschildren
más-

Estoy tratando de encontrar la forma adecuada de definir algunos componentes que podrían usarse de manera genérica:

<Parent>
  <Child value="1">
  <Child value="2">
</Parent>

Por supuesto, existe una lógica para la representación entre los componentes principal y secundario, se puede imaginar <select> y <option> como ejemplo de esta lógica.

Esta es una implementación ficticia para el propósito de la pregunta:

var Parent = React.createClass({
  doSomething: function(value) {
  },
  render: function() {
    return (<div>{this.props.children}</div>);
  }
});

var Child = React.createClass({
  onClick: function() {
    this.props.doSomething(this.props.value); // doSomething is undefined
  },
  render: function() {
    return (<div onClick={this.onClick}></div>);
  }
});

La pregunta es cada vez que usas {this.props.children} para definir un componente contenedor, ¿cómo se transmite alguna propiedad a todos sus elementos secundarios?

  • Aprendí mucho de las respuestas a esta pregunta. Creo que la API de contexto es la mejor solución en la tierra de React de hoy. Pero si quieres usar React.cloneElement, un problema que enfrenté es no iterar correctamente a los niños con React.Children.map(). Ver más en Cómo pasar accesorios a {react.children}

    – Víctor Ofoegbu

    26 de mayo de 2021 a las 3:23

Como pasar accesorios a thispropschildren
Andrés F García

Para una forma un poco más limpia de hacerlo, intente:

<div>
    {React.cloneElement(this.props.children, { loggedIn: this.state.loggedIn })}
</div>

Editar: para usar con varios niños individuales (el niño en sí mismo debe ser un componente), puede hacerlo. Probado en 16.8.6

<div>
    {React.cloneElement(this.props.children[0], { loggedIn: true, testPropB: true })}
    {React.cloneElement(this.props.children[1], { loggedIn: true, testPropA: false })}
</div>

  • Estaba usando la respuesta más calificada, ¡pero esta es mucho más sencilla! Esta solución también es la que usan en la página de ejemplos de react-router.

    – captDaylight

    09/03/2016 a las 14:30

  • ¿Alguien podría explicar cómo funciona esto (o lo que realmente hace)? Leer los documentos, no podía ver cómo esto descendería a los niños y agregaría ese accesorio a cada niño: ¿es eso lo que pretende hacer? Si lo hace, ¿cómo sabemos que esto es lo que hará? No es nada obvio que incluso sea válido pasar una estructura de datos opaca (this.props.children) para cloneElement … que espera un … elemento.

    – GreenAsJade

    28/03/2016 a las 21:55

  • Exactamente, esto no parece funcionar con más de un niño.

    – Danita

    29 de marzo de 2016 a las 12:22

  • Entonces, puede escribir código que funcione mientras alguien pasa solo un elemento secundario a un componente, pero cuando agregan otro, falla … ¿eso no suena bien a primera vista? Parecería ser una trampa para el OP, quien preguntó específicamente sobre pasar accesorios a todos niños.

    – GreenAsJade

    5 de mayo de 2016 a las 12:23


  • @GreenAsJade está bien siempre que su componente esté esperando un solo hijo. Puede definir a través de sus componentes propTypes que espera un solo hijo. React.Children.only la función devuelve el único hijo o lanza una excepción si hay varios (esto no existiría si no hubiera un caso de uso).

    – cchamberlain

    5 mayo 2016 a las 18:14

  • ¿Es posible volver? React.cloneElement() directamente sin rodearlo <div> etiquetas? Porque ¿y si el niño es un <span> (o algo más) y queremos conservar su tipo de elemento de etiqueta?

    – adrianmc

    17 de diciembre de 2016 a las 3:45

  • Si es un niño, puede omitir el envoltorio y esta solución solo funciona para un niño, así que sí.

    – ThaJay

    15 de marzo de 2017 a las 11:48

  • Funciona para mi. Sin encerrar

    está bien.

    – Anulación de choque

    8 mayo 2017 a las 18:22

  • Si necesita hacer cumplir explícitamente que solo recibe un hijo, puede hacerlo React.cloneElement(React.Children.only(this.props.children), {...this.props}) lo que arrojará un error si se pasa a más de un niño. Entonces no necesita envolver en un div.

    – itsananderson

    21 de agosto de 2017 a las 22:05


  • Esta respuesta puede producir un TypeError: valor de objeto cíclico. A menos que desee que uno de los accesorios del niño sea él mismo, use let {children, ...acyclicalProps} = this.props y luego React.cloneElement(React.Children.only(children), acyclicalProps).

    – Parabolord

    16 de junio de 2018 a las 18:57


1646959629 477 Como pasar accesorios a thispropschildren
Liubomir

Pase accesorios para dirigir a los niños.

Ver todas las demás respuestas

Pase datos globales compartidos a través del árbol de componentes a través de contexto

El contexto está diseñado para compartir datos que pueden considerarse “globales” para un árbol de componentes de React, como el usuario autenticado actual, el tema o el idioma preferido. 1

Descargo de responsabilidad: esta es una respuesta actualizada, la anterior usaba la API de contexto anterior

Se basa en el principio Consumidor / Proveer. Primero, crea tu contexto

const { Provider, Consumer } = React.createContext(defaultValue);

A continuación, utilice a través de

<Provider value={/* some value */}>
  {children} /* potential consumers */
</Provider>

y

<Consumer>
  {value => /* render something based on the context value */}
</Consumer>

Todos los Consumidores que son descendientes de un Proveedor volverán a renderizar cada vez que cambie la propuesta de valor del Proveedor. La propagación del Proveedor a sus Consumidores descendientes no está sujeta al método shouldComponentUpdate, por lo que el Consumidor se actualiza incluso cuando un componente ancestro sale de la actualización. 1

Ejemplo completo, semi-pseudocódigo.

import React from 'react';

const { Provider, Consumer } = React.createContext({ color: 'white' });

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: { color: 'black' },
    };
  }

  render() {
    return (
      <Provider value={this.state.value}>
        <Toolbar />
      </Provider>
    );
  }
}

class Toolbar extends React.Component {
  render() {
    return ( 
      <div>
        <p> Consumer can be arbitrary levels deep </p>
        <Consumer> 
          {value => <p> The toolbar will be in color {value.color} </p>}
        </Consumer>
      </div>
    );
  }
}

1 https://facebook.github.io/react/docs/context.html

  • A diferencia de la respuesta aceptada, esto funcionará correctamente incluso cuando haya otros elementos incluidos en Parent. Esta es definitivamente la mejor respuesta.

    – Zaptree

    11/09/2016 a las 23:36

  • ¡Accesorios! = contexto

    – Petr Peller

    11 de diciembre de 2016 a las 19:14

  • no puede depender de los cambios que se propagan a través del contexto. Usa accesorios cuando sea posible que cambien.

    – ThaJay

    15/03/2017 a las 11:50

  • Tal vez no entiendo, pero ¿no está mal decir “el contexto hace que los accesorios estén disponibles”? La última vez que usé el contexto, era una cosa separada (es decir, this.context)–no fusionó mágicamente el contexto con los accesorios. Tenías que establecer y usar intencionalmente el contexto, que es otra cosa.

    – José

    21 de abril de 2017 a las 12:37

  • Lo entiendes perfectamente, era incorrecto. He editado mi respuesta.

    – Liubomir

    21 de abril de 2017 a las 12:43

Pasar accesorios a niños anidados

Con la actualización a Reaccionar 16.6 ahora puedes usar Reaccionar.createContext y contextType.

import * as React from 'react';

// React.createContext accepts a defaultValue as the first param
const MyContext = React.createContext(); 

class Parent extends React.Component {
  doSomething = (value) => {
    // Do something here with value
  };

  render() {
    return (
       <MyContext.Provider value={{ doSomething: this.doSomething }}>
         {this.props.children}
       </MyContext.Provider>
    );
  }
}
 
class Child extends React.Component {
  static contextType = MyContext;

  onClick = () => {
    this.context.doSomething(this.props.value);
  };      

  render() {
    return (
      <div onClick={this.onClick}>{this.props.value}</div>
    );
  }
}

// Example of using Parent and Child

import * as React from 'react';

class SomeComponent extends React.Component {

  render() {
    return (
      <Parent>
        <Child value={1} />
        <Child value={2} />
      </Parent>
    );
  }
}

Reaccionar.createContext brilla donde React.clonElement el caso no pudo manejar componentes anidados

class SomeComponent extends React.Component {

  render() {
    return (
      <Parent>
        <Child value={1} />
        <SomeOtherComp><Child value={2} /></SomeOtherComp>
      </Parent>
    );
  }
}

  • A diferencia de la respuesta aceptada, esto funcionará correctamente incluso cuando haya otros elementos incluidos en Parent. Esta es definitivamente la mejor respuesta.

    – Zaptree

    11/09/2016 a las 23:36

  • ¡Accesorios! = contexto

    – Petr Peller

    11 de diciembre de 2016 a las 19:14

  • no puede depender de los cambios que se propagan a través del contexto. Usa accesorios cuando sea posible que cambien.

    – ThaJay

    15/03/2017 a las 11:50

  • Tal vez no entiendo, pero ¿no está mal decir “el contexto hace que los accesorios estén disponibles”? La última vez que usé el contexto, era una cosa separada (es decir, this.context)–no fusionó mágicamente el contexto con los accesorios. Tenías que establecer y usar intencionalmente el contexto, que es otra cosa.

    – José

    21 de abril de 2017 a las 12:37

  • Lo entiendes perfectamente, era incorrecto. He editado mi respuesta.

    – Liubomir

    21 de abril de 2017 a las 12:43

La mejor manera, que le permite hacer la transferencia de propiedad es children como un patrón de función
https://medium.com/merrickchristensen/function-as-child-components-5f3920a9ace9

Fragmento de código: https://stackblitz.com/edit/react-fcmubc

Ejemplo:

const Parent = ({ children }) => {
    const somePropsHere = {
      style: {
        color: "red"
      }
      // any other props here...
    }
    return children(somePropsHere)
}

const ChildComponent = props => <h1 {...props}>Hello world!</h1>

const App = () => {
  return (
    <Parent>
      {props => (
        <ChildComponent {...props}>
          Bla-bla-bla
        </ChildComponent>
      )}
    </Parent>
  )
}

  • Esto me parece mucho más sencillo (¿y mejor para el rendimiento?) Que la respuesta aceptada.

    – Shikyō

    3 de marzo de 2019 a las 6:22

  • Esto requiere que los niños sean una función y no funciona para los componentes anidados.

    – ilusión digital

    30 de abril de 2019 a las 8:47

  • @digitalillusion, no entiendo que significa nested components. React no tiene patrones anidados, solo composiciones. Sí, los niños deben ser una función, no hay ningún conflicto, porque este es un niño JSX válido. ¿Puedes dar un ejemplo con nesting components ?

    – Nick Ovchinnikov

    1 de mayo de 2019 a las 9:09

  • Tiene razón, el caso de los niños profundamente anidados también se puede manejar <Parent>{props => <Nest><ChildComponent /></Nest>}</Parent> en lugar de (no funciona) <Parent><Nest>{props => <ChildComponent />}</Nest></Parent> entonces estoy de acuerdo esta es la mejor respuesta

    – ilusión digital

    2 de mayo de 2019 a las 9:33

  • Al intentar, recibo lo siguiente: TypeError: children is not a function

    –Ryan Prentiss

    30 de octubre de 2019 a las 7:15

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad