tutorial react instalar hello example español ejemplos javascript reactjs react-jsx

javascript - instalar - react js init



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

Pasar accesorios a niños anidados

Con la actualización a React 16.6 ahora puede usar React.createContext y contextType .

class SomeComponent extends React.Component { render() { return ( <Parent> <Child value={1} /> <SomeOtherComp><Child value={2} /></SomeOtherComp> </Parent> ); } }

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

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

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

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

Por supuesto, hay una lógica para representar entre los componentes principales y secundarios, puede imaginar <select> y <option> como un 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 utiliza {this.props.children} para definir un componente contenedor, ¿cómo se {this.props.children} alguna propiedad a todos sus elementos secundarios?


Pase accesorios para dirigir a los niños.

Ver todas las otras respuestas

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

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

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

Se basa en el principio de consumidor / proporcionar. Primero, crea tu contexto

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

Luego use vía

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

y

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> ); } }

Todos los consumidores que sean descendientes de un proveedor se volverán a procesar cada vez que cambie el valor de apoyo 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 abandona la actualización. 1

Ejemplo completo, semi-pseudocódigo.

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> ); } }

1 context


Método 1 - clonar niños

export const Context = createContext<any>(null); export const ComposableContext = ({ children, ...otherProps }:{children:ReactNode, [x:string]:any}) => { const context = useContext(Context) return( <Context.Provider {...context} value={{...context, ...otherProps}}>{children}</Context.Provider> ); } function App() { return ( <Provider1> <Provider2> <Displayer /> </Provider2> </Provider1> ); } const Provider1 =({children}:{children:ReactNode}) => ( <ComposableContext greeting="Hello">{children}</ComposableContext> ) const Provider2 =({children}:{children:ReactNode}) => ( <ComposableContext name="world">{children}</ComposableContext> ) const Displayer = () => { const context = useContext(Context); return <div>{context.greeting}, {context.name}</div>; };

Método 2: usar contexto composable

El contexto le permite pasar un accesorio a un componente secundario profundo sin pasarlo explícitamente como accesorio a través de los componentes intermedios.

El contexto viene con inconvenientes:

  1. Los datos no fluyen de la manera regular, a través de accesorios.
  2. El uso del contexto crea un contrato entre el consumidor y el proveedor. Puede ser más difícil de entender y replicar los requisitos necesarios para reutilizar un componente.

Usando un contexto composable

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


¿Es esto lo que necesitabas?

var newChildren = this.props.children.map((child) => { const className = "MenuTooltip-item " + child.props.className; return React.cloneElement(child, { className }); }); return <div>{newChildren}</div>;


Además de la respuesta @and_rest, así es como clono a los niños y agrego una clase.

const Parent = ({children}) => { const doSomething(value) => {} return children({ doSomething }) }


Creo que un accesorio de render es la forma adecuada de manejar este escenario

Dejas que el padre proporcione los accesorios necesarios utilizados en el componente hijo, refactorizando el código principal para que se vea de la siguiente manera:

class Child extends React { onClick() => { this.props.doSomething } render() { return (<div onClick={this.onClick}></div>); } }

Luego, en el componente secundario, puede acceder a la función provista por el padre de esta manera:

<Parent> {(doSomething) => (<Fragment> <Child value="1" doSomething={doSomething}> <Child value="2" doSomething={doSomething}> <Fragment /> )} </Parent>

Ahora la estructura final se verá así:

{React.cloneElement(this.props.children, this.props)}


De acuerdo con la documentación de cloneElement()

<element.type {...element.props} {...props}>{children}</element.type>

Clonar y devolver un nuevo elemento Reaccionar utilizando el elemento como punto de partida. El elemento resultante tendrá los accesorios del elemento original con los nuevos accesorios fusionados en forma superficial. Los nuevos niños reemplazarán a los niños existentes. La clave y la referencia del elemento original se conservarán.

React.cloneElement() es casi equivalente a:

render() { const newElements = []; React.Children.forEach(this.props.children, child => newElements.push( React.cloneElement( child, {...this.props, ...customProps} ) ) ) return ( <div>{newElements}</div> ) }

Sin embargo, también conserva las referencias. Esto significa que si obtienes un niño con un árbitro, no lo robarás accidentalmente de tu antepasado. Obtendrá la misma referencia adjunta a su nuevo elemento.

Entonces cloneElement es lo que usarías para proporcionar accesorios personalizados a los niños. Sin embargo, puede haber varios elementos secundarios en el componente y necesitaría recorrerlo. Lo que otras respuestas sugieren es que las React.Children.map usando React.Children.map . Sin embargo, React.Children.map diferencia de React.cloneElement cambia las claves del elemento que se agrega y extra .$ Como prefijo. Consulte esta pregunta para obtener más detalles: React.cloneElement dentro de React.Children.map está causando cambios en las claves de los elementos

Si desea evitarlo, debe forEach por la función forEach como

render() { let updatedChildren = React.Children.map(this.props.children, (child) => { return React.cloneElement(child, { newProp: newProp }); }); return ( <div> { updatedChildren } </div> ); }


La forma más hábil de hacer esto:

{React.isValidElement(this.props.children) ? React.cloneElement(this.props.children, { ...prop_you_want_to_pass }) : null}


La mejor manera, que le permite hacer la transferencia de propiedad es a los children como una función

Ejemplo:

<BrowserRouter> <div> <ul> <li><Link to="/">Home</Link></li> <li><Link to="/posts">Posts</Link></li> <li><Link to="/about">About</Link></li> </ul> <hr/> <Route path="/" exact component={Home} /> <Route path="/posts" render={() => ( <Posts value1={1} value2={2} data={this.state.data} /> )} /> <Route path="/about" component={About} /> </div> </BrowserRouter>


Manera más limpia considerando uno o más niños

// Render method of Parent component render(){ let props = { setAlert : () => {alert("It works")} }; let childrenWithProps = React.Children.map( this.props.children, function(child) { if (React.isValidElement(child)){ return React.cloneElement(child, props); } return child; }); return <div>{childrenWithProps}</div> }


Necesitaba corregir la respuesta aceptada arriba para que funcione usando eso en lugar de este puntero. Esto dentro del alcance de la función de mapa no tenía definida la función doSomething .

<div> { React.Children.map(this.props.children, child => React.cloneElement(child, {...this.props}))} </div>

Actualización: esta solución es para ECMAScript 5, en ES6 no hay necesidad en var que = esto


Ninguna de las respuestas aborda el problema de tener hijos que NO sean componentes React, como cadenas de texto. Una solución alternativa podría ser algo como esto:

import React from ''react''; const doSomething = value => {}; const Parent = props => ( <div> { !props || !props.children ? <div>Loading... (required at least one child)</div> : !props.children.length ? <props.children.type {...props.children.props} doSomething={doSomething} {...props}>{props.children}</props.children.type> : props.children.map((child, key) => React.cloneElement(child, {...props, key, doSomething})) } </div> );


Para cualquiera que tenga un solo elemento hijo, esto debería hacerlo.

const Parent = (props) => { const attributeToAddOrReplace= "Some Value" const childrenWithAdjustedProps = React.Children.map(props.children, child => React.cloneElement(child, { attributeToAddOrReplace}) ); return <div>{childrenWithAdjustedProps }</div> }


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

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

Editar: para usar con varios elementos secundarios individuales (el elemento secundario debe ser un componente) que puede hacer. Probado en 16.8.6

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


Parent.jsx:

import React from ''react''; /* but better import doSomething right here, or use some flux store (for example redux library) */ export default ({ doSomething, value }) => ( <div onClick={() => doSomething(value)}/> );

Child.jsx:

import React from ''react''; import { render } from ''react-dom''; import Parent from ''./Parent''; import Child from ''./Child''; render( <Parent> <Child/> <Child value=''1''/> <Child value=''2''/> </Parent>, document.getElementById(''...'') );

y main.jsx:

React.cloneElement( element, [props], [...children] )

ver ejemplo aquí: https://plnkr.co/edit/jJHQECrKRrtKlKYRpIWl?p=preview


Por alguna razón, React.children no funcionaba para mí. Esto es lo que funcionó para mí.

Solo quería agregar una clase al niño. similar a cambiar un accesorio

class Child extends React.Component { render() { return <div className="Child"> Child <p onClick={this.props.doSomething}>Click me</p> {this.props.a} </div>; } } class Parent extends React.Component { doSomething(){ alert("Parent talks"); } render() { return <div className="Parent"> Parent {this.props.render({ anythingToPassChildren:1, doSomething: this.doSomething})} </div>; } } class Application extends React.Component { render() { return <div> <Parent render={ props => <Child {...props} /> }/> </div>; } }

El truco aquí es el React.cloneElement . Puedes pasar cualquier accesorio de manera similar


Prueba esto

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

Funcionó para mí usando react-15.1.


Puede usar React.cloneElement , es mejor saber cómo funciona antes de comenzar a usarlo en su aplicación. Se presenta en React v0.13 , React v0.13 leyendo para obtener más información, así que algo junto con este trabajo para ti:

React.cloneElement(element, props, ...children);

Así que traiga las líneas de la documentación de React para que comprenda cómo funciona todo y cómo puede utilizarlas:

En React v0.13 RC2 presentaremos una nueva API, similar a React.addons.cloneWithProps, con esta firma:

<element.type {...element.props} {...props}>{children}</element.type>

A diferencia de cloneWithProps, esta nueva función no tiene ningún comportamiento mágico incorporado para fusionar estilo y className por la misma razón por la que no tenemos esa característica de transferPropsTo. Nadie está seguro de cuál es exactamente la lista completa de cosas mágicas, lo que dificulta razonar sobre el código y es difícil de reutilizar cuando el estilo tiene una firma diferente (por ejemplo, en el próximo React Native).

React.cloneElement es casi equivalente a:

var newChildren = React.Children.map(this.props.children, function(child) { return React.cloneElement(child, { foo: true }) });

Sin embargo, a diferencia de JSX y cloneWithProps, también conserva las referencias. Esto significa que si obtienes un niño con un árbitro, no lo robarás accidentalmente de tu antepasado. Obtendrá la misma referencia adjunta a su nuevo elemento.

Un patrón común es mapear a sus hijos y agregar un nuevo accesorio. Se informaron muchos problemas sobre cloneWithProps que perdió la referencia, por lo que es más difícil razonar sobre su código. Ahora, siguiendo el mismo patrón con cloneElement funcionará como se esperaba. Por ejemplo:

export const GrantParent = () => { return ( <Parent> {props => ( <ChildComponent {...props}> Bla-bla-bla </ChildComponent> )} </Parent> ) } export const Parent = ({ children }) => { const somePropsHere = { //...any } <> {children(somePropsHere)} </> }

Nota: React.cloneElement (child, {ref: ''newRef''}) ANULA la referencia, por lo que todavía no es posible que dos padres tengan una referencia para el mismo elemento secundario, a menos que use callback-refs.

Esta fue una característica crítica para entrar en React 0.13 ya que los accesorios ahora son inmutables. La ruta de actualización a menudo es para clonar el elemento, pero al hacerlo puede perder la referencia. Por lo tanto, necesitábamos una mejor ruta de actualización aquí. Cuando estábamos actualizando los sitios de llamadas en Facebook nos dimos cuenta de que necesitábamos este método. Recibimos los mismos comentarios de la comunidad. Por lo tanto, decidimos hacer otro RC antes del lanzamiento final para asegurarnos de tener esto en cuenta.

Planeamos desaprobar eventualmente React.addons.cloneWithProps. Todavía no lo estamos haciendo, pero esta es una buena oportunidad para comenzar a pensar en sus propios usos y considerar usar React.cloneElement en su lugar. Nos aseguraremos de enviar un lanzamiento con avisos de desaprobación antes de que realmente lo eliminemos, por lo que no es necesaria ninguna acción inmediata.

más here ...


Si tiene varios hijos a los que desea pasar accesorios , puede hacerlo de esta manera, utilizando el mapa React.Children.map:

render() { return ( <div> { React.cloneElement(this.props.children, { newProp: newProp }) } </div> ); }

Si su componente tiene solo un hijo, no hay necesidad de mapear, simplemente puede clonarElement de inmediato:

<div className="parent"> {React.Children.map(this.props.children, child => React.cloneElement(child, {className:''child''}))} </div>


Tal vez también pueda encontrar útil esta función, aunque muchas personas lo han considerado como un antipatrón, todavía se puede usar si sabe lo que está haciendo y diseña bien su solución.

Funcionan como componentes secundarios


Ya no necesitas {this.props.children} . Ahora puedes envolver tu componente hijo usando render en Route y pasar tus accesorios como de costumbre:

var Parent = React.createClass({ doSomething: function() { console.log(''doSomething!''); }, render: function() { var that = this; var childrenWithProps = React.Children.map(this.props.children, function(child) { return React.cloneElement(child, { doSomething: that.doSomething }); }); return <div>{childrenWithProps}</div> }})


Render props es el enfoque más preciso para este problema. En lugar de pasar el componente hijo al componente padre como accesorios hijos, deje que el padre represente el componente hijo manualmente. Render es accesorios integrados en react, que toma el parámetro de función. En esta función, puede permitir que el componente principal represente lo que desee con parámetros personalizados. Básicamente, hace lo mismo que los accesorios para niños, pero es más personalizable.

class Child extends React.Component { render() { return <div className="Child"> Child <p onClick={this.props.doSomething}>Click me</p> {this.props.a} </div>; } } class Parent extends React.Component { doSomething(){ alert("Parent talks"); } render() { return <div className="Parent"> Parent {this.props.render({ anythingToPassChildren:1, doSomething: this.doSomething})} </div>; } } class Application extends React.Component { render() { return <div> <Parent render={ props => <Child {...props} /> }/> </div>; } }

Ejemplo en codepen


Clonando niños con nuevos accesorios

Puede usar React.Children para iterar sobre los hijos y luego clonar cada elemento con nuevos accesorios (fusión superficial) usando React.cloneElement por ejemplo:

const Child = ({ doSomething, value }) => ( <div onClick={() => doSomething(value)}>Click Me</div> ); class Parent extends React.PureComponent { doSomething = (value) => { console.log(''doSomething called by child with value:'', value); } render() { const childrenWithProps = React.Children.map(this.props.children, child => React.cloneElement(child, { doSomething: this.doSomething }) ); return <div>{childrenWithProps}</div> } }; ReactDOM.render( <Parent> <Child value="1" /> <Child value="2" /> </Parent>, document.getElementById(''container'') );

Violín: https://jsfiddle.net/2q294y43/2/

Llamar a los niños como una función

También puede pasar accesorios a niños con accesorios de render . En este enfoque, los hijos (que pueden ser children o cualquier otro nombre de utilería) es una función que puede aceptar cualquier argumento que desee pasar y devuelve los hijos:

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

En lugar de <React.Fragment> o simplemente <> también puede devolver una matriz si lo prefiere.

Fiddle: https://jsfiddle.net/ferahl/y5pcua68/7/