소품을 {this.props.children}에 전달하는 방법


888

일반적인 방법으로 사용할 수있는 일부 구성 요소를 정의하는 올바른 방법을 찾으려고합니다.

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

물론 부모와 자녀 구성 요소 사이의 렌더링에가는 논리가있다, 당신은 상상할 수 <select><option>이 논리의 예로서.

이것은 질문의 목적으로 더미 구현입니다.

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

문제는 {this.props.children}래퍼 구성 요소를 정의하는 데 사용할 때마다 모든 자식에게 일부 속성을 어떻게 전달합니까?


답변:


955

새로운 소품으로 어린이 복제

당신은 사용할 수 있습니다 React.Children를 복제 한 후 새로운 소품 (얕은 병합)를 사용하여 각 요소를 자식들에 대해 반복하고, React.cloneElement을 예를 들면 :

import React, { Children, isValidElement, cloneElement } from 'react';

const Child = ({ doSomething, value }) => (
  <div onClick={() => doSomething(value)}>Click Me</div>
);

function Parent({ children }) {
  function doSomething(value) {
    console.log('doSomething called by child with value:', value);
  }

  render() {
    const childrenWithProps = Children.map(children, child => {
      // Checking isValidElement is the safe way and avoids a TS error too.
      if (isValidElement(child)) {
        return cloneElement(child, { doSomething })
      }

      return child;
    });

    return <div>{childrenWithProps}</div>
  }
};

ReactDOM.render(
  <Parent>
    <Child value="1" />
    <Child value="2" />
  </Parent>,
  document.getElementById('container')
);

피들 : https://jsfiddle.net/2q294y43/2/

함수로 어린이 호출

렌더링 소품을 사용 하여 소품을 어린이에게 전달할 수도 있습니다 . 이 접근법에서 자식 ( children또는 다른 소품 이름 일 수 있음 )은 전달하려는 인수를 허용하고 자식을 반환하는 함수입니다.

const Child = ({ doSomething, value }) => (
  <div onClick={() =>  doSomething(value)}>Click Me</div>
);

function Parent({ children }) {
  function doSomething(value) {
    console.log('doSomething called by child with value:', value);
  }

  render() {
    // Note that children is called as a function and we can pass args to it
    return <div>{children(doSomething)}</div>
  }
};

ReactDOM.render(
  <Parent>
    {doSomething => (
      <React.Fragment>
        <Child doSomething={doSomething} value="1" />
        <Child doSomething={doSomething} value="2" />
      </React.Fragment>
    )}
  </Parent>,
  document.getElementById('container')
);

원하는 경우 대신 <React.Fragment>또는 단순히 <>배열을 반환 할 수도 있습니다.

피들 : https://jsfiddle.net/ferahl/y5pcua68/7/


7
이것은 나를 위해 작동하지 않습니다. 이것은 React.cloneElement () 안에 정의되어 있지 않습니다
Patrick

12
이 답변은 작동하지 않습니다 value에 전달 doSomething손실됩니다.
Dave

3
@DominicTobias Arg, 죄송합니다. console.log를 경고로 바꾸고 두 매개 변수를 단일 문자열로 연결하는 것을 잊었습니다.
Dave

1
이 답변은 매우 도움이되었지만 여기에 언급되지 않은 문제가 발생하여 새로운 것이 있는지 또는 내 말이 이상한 것인지 궁금합니다. 자식 요소를 복제 할 때 this.props.children.props.children을 cloneElement의 세 번째 인수에 추가 할 때까지 자식 요소가 이전 요소로 설정되었습니다.
aphenine

7
자식이 별도의 경로 페이지에서로드 된 경로 (v4)를 통해로드되면 어떻게됩니까?
blamb

394

약간 더 깔끔한 방법으로 시도해보십시오.

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

편집 : 여러 개별 자녀와 함께 사용하려면 (자녀 자체가 구성 요소이어야 함) 할 수 있습니다. 16.8.6에서 테스트

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

10
나는 가장 등급이 높은 답변을 사용했지만이 답변은 훨씬 더 간단합니다! 이 솔루션은 반응 라우터 예제 페이지에서도 사용됩니다.
captDaylight

10
누군가 이것이 어떻게 작동하는지 (또는 실제로 무엇을하는지) 설명 할 수 있습니까? 읽기 워드 프로세서를 , 나는이 아이들에 내려 각각의 아이에게 그 소품을 추가하는 방법을 볼 수 없었다 -가 수행하는 역할이 무엇입니까? 그렇다면 어떻게해야하는지 어떻게 알 수 있습니까? 불투명 한 데이터 구조 ( this.props.children)를 전달하는 것이 유효하다는 것은 전혀 분명하지 않습니다 cloneElement. ... ... 요소를 기대합니다.
GreenAsJade

51
정확히, 이것은 둘 이상의 어린이와 함께 작동하지 않는 것 같습니다.
Danita

17
따라서 누군가 한 명의 자녀 만 구성 요소에 전달하는 동안 작동하는 코드를 작성할 수는 있지만 다른 자녀를 추가하면 충돌이 발생합니다 ... 액면 가치가 좋지 않습니까? 그것은 모든 어린이들에게 소품을 전달하는 것에 대해 구체적으로 물었던 OP의 함정 인 것 같습니다 .
GreenAsJade 12

10
@GreenAsJade는 구성 요소가 단일 자식을 기대하는 한 훌륭합니다. 구성 요소 propTypes를 통해 단일 하위 항목을 예상 할 수 있습니다. React.Children.only함수는 유일한 자식을 반환하거나 여러 개가있는 경우 예외를 발생시킵니다 (사용 사례가없는 경우 존재하지 않음).
cchamberlain

80

이 시도

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

react-15.1을 사용하여 나를 위해 일했습니다.


3
태그 React.cloneElement()를 둘러싸 지 않고 직접 반환 할 수 <div>있습니까? 자식이 <span>(또는 다른 것)이고 태그 요소 유형을 유지하려면 어떻게해야합니까?
adrianmc

1
그것이 한 아이라면 래퍼를 제외 하고이 솔루션은 한 아이에게만 유효합니다. 그렇습니다.
ThaJay

1
나를 위해 작동합니다. <div>를 묶지 않으면 괜찮습니다.
충돌 무시

4
한 명의 자녀 만 받도록 명시 적으로 시행해야하는 React.cloneElement(React.Children.only(this.props.children), {...this.props})경우 여러 명의 자녀에게 전달 된 경우 오류가 발생할 수 있습니다. 그런 다음 div를 래핑 할 필요가 없습니다.
itsananderson

1
이 답변은 TypeError : cyclic object value를 생성 할 수 있습니다. 자녀의 소품 중 하나가 스스로되기를 원하지 않는다면, let {children, ...acyclicalProps} = this.propsand을 사용하십시오 React.cloneElement(React.Children.only(children), acyclicalProps).
Parabolord

68

어린이들에게 소품을 전달하십시오.

다른 답변 모두보기

컨텍스트 를 통해 컴포넌트 트리를 통해 공유 된 글로벌 데이터 전달

컨텍스트는 현재 인증 된 사용자, 테마 또는 선호 언어와 같은 React 컴포넌트 트리에 대해 "전역"으로 간주 될 수있는 데이터를 공유하도록 설계되었습니다. 1

면책 조항 : 이것은 업데이트 된 답변이며, 이전 답변은 이전 컨텍스트 API를 사용했습니다.

소비자 / 제공 원칙을 기반으로합니다. 먼저 컨텍스트를 작성하십시오.

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

그런 다음 통해 사용

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

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

제공자의 후손 인 모든 소비자는 제공자의 가치 제안이 변경 될 때마다 다시 렌더링됩니다. 공급자에서 하위 소비자로의 전파에는 shouldComponentUpdate 메소드가 적용되지 않으므로 조상 구성 요소가 업데이트에서 종료 될 때에도 소비자가 업데이트됩니다. 1

전체 예, 세미 의사 코드

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


6
허용 된 답변과 달리 이것은 부모 아래에 다른 요소가 포함되어 있어도 올바르게 작동합니다. 이것이 가장 좋은 대답입니다.
Zaptree

6
Props! = context
Petr Peller

컨텍스트를 통해 전파되는 변경 사항에 의존 할 수 없습니다. 소품이 변할 수 있으면 소품을 사용하십시오.
ThaJay

1
어쩌면 나는 이해하지 못하지만 "문맥이 소품을 사용할 수있게 만든다"고 말하는 것이 잘못이 아닌가? 문맥을 마지막으로 사용했을 때, 그것은 별개의 것입니다 (즉 this.context, 문맥과 소품을 마술처럼 합치 지 않았습니다). 컨텍스트를 의도적으로 설정하고 사용해야했습니다. 이는 완전히 다른 것입니다.
Josh

당신은 완벽하게 이해합니다, 그것은 틀 렸습니다. 내 답변을 편집했습니다.
Lyubomir

48

중첩 된 어린이에게 소품 전달

React 16.6으로 업데이트 하면 이제 React.createContextcontextType을 사용할 수 있습니다 .

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

React.createContextReact.cloneElement 케이스가 중첩 된 컴포넌트를 처리 할 수없는 곳에서 빛납니다

class SomeComponent extends React.Component {

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

3
왜 => 함수가 나쁜 습관인지 설명 할 수 있습니까? => 기능을하는 데 도움이 바인드 이벤트 핸들러 얻기 위해 this컨텍스트
케네스의 Truong

@KennethTruong은 렌더링 할 때마다 함수를 생성하기 때문에
itdoesntwork

9
사실이 아닌 @itdoesntwork. 클래스를 만들 때만 새 함수를 만듭니다. 렌더링 기능 중에는 생성되지 않습니다.
Kenneth Truong

@KennethTruong reactjs.org/docs/faq-functions.html#arrow-function-in-render 렌더링에서 화살표 기능에 대해 이야기하고 있다고 생각했습니다.
itdoesntwork

24

을 사용할 수 있습니다 React.cloneElement. 애플리케이션에서 사용하기 전에 작동 방식을 아는 것이 좋습니다. 에 소개되어 React v0.13있으며 자세한 정보는 다음을 참조하십시오.

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

따라서 React 문서의 라인을 가져 와서 모든 것이 어떻게 작동하고 어떻게 사용할 수 있는지 이해하십시오.

React v0.13 RC2에서는 React.addons.cloneWithProps와 유사한이 API를 사용하여 새로운 API를 소개합니다.

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

cloneWithProps와 달리이 새로운 함수에는 transferPropsTo에 해당 기능이없는 것과 같은 이유로 스타일과 className을 병합하기위한 마법의 내장 동작이 없습니다. 마술의 전체 목록이 정확히 무엇인지 확실하지 않은 사람은 아무도 코드에 대해 추론하기가 어렵고 스타일에 다른 서명이있을 때 재사용하기가 어렵습니다 (예 : 다가오는 React Native).

React.cloneElement는 다음과 거의 같습니다.

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

그러나 JSX 및 cloneWithProps와 달리 심판도 보존합니다. 이것은 당신이 그것에 심판을 가진 아이를 얻는다면, 실수로 조상으로부터 아이를 훔치지 않을 것임을 의미합니다. 새 요소에 동일한 참조가 첨부됩니다.

일반적인 패턴 중 하나는 자녀를지도에 표시하고 새로운 소품을 추가하는 것입니다. cloneWithProps가 심판을 잃어버린 것에 대해 많은 문제 가보고되어 코드를 추론하기가 더 어려워졌습니다. 이제 cloneElement와 동일한 패턴을 따르는 것이 예상대로 작동합니다. 예를 들면 다음과 같습니다.

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

참고 : React.cloneElement (child, {ref : 'newRef'}) 참조를 재정의하므로 콜백 참조를 사용하지 않으면 두 부모가 동일한 자식에 대한 참조를 가질 수 없습니다.

소품은 이제 불변이기 때문에 이것은 React 0.13에 들어가는 중요한 기능이었습니다. 업그레이드 경로는 종종 요소를 복제하는 것이지만 그렇게하면 심판을 잃을 수 있습니다. 따라서 더 나은 업그레이드 경로가 필요했습니다. Facebook에서 콜 사이트를 업그레이드 할 때이 방법이 필요하다는 것을 깨달았습니다. 우리는 커뮤니티로부터 동일한 피드백을 받았습니다. 따라서 우리는 최종 출시 전에 다른 RC를 만들어 결정했습니다.

결국 React.addons.cloneWithProps를 더 이상 사용하지 않을 계획입니다. 아직 수행하지는 않았지만 이것은 자신의 용도에 대해 생각하고 대신 React.cloneElement를 사용하는 것을 고려할 수있는 좋은 기회입니다. 실제로 제거하기 전에 사용 중단 알림이 포함 된 릴리스를 제공하므로 즉각적인 조치가 필요하지 않습니다.

여기에 ...


18

재산을 양도 할 수있는 가장 좋은 방법 children은 기능과 같습니다

예:

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

export const Parent = ({ children }) => {
    const somePropsHere = { //...any }
    <>
        {children(somePropsHere)}
    </>
}

1
이것은 받아 들인 대답보다 훨씬 간단하고 성능이 좋습니까?
Shikyo

2
이를 위해서는 어린이가 기능을 수행해야하며 깊이 중첩 된 구성 요소에는 작동하지 않습니다.
디지털 환상

@digitalillusion, 나는 그것이 무엇을 의미하는지 이해하지 못합니다 nested components. React에는 중첩 패턴이 없으며 컴포지션 만 있습니다. 예, 자식은 함수 여야합니다. 유효한 JSX 자식이므로 충돌이 없습니다. 예를 들어 주실 수 있습니까 nesting components?
Nick Ovchinnikov

1
당신은 깊게 중첩 된 아이들 <Parent>{props => <Nest><ChildComponent /></Nest>}</Parent>이 (작동하지 않는) 대신 처리 될 수 있다는 것이 옳습니다. <Parent><Nest>{props => <ChildComponent />}</Nest></Parent>그래서 이것이 최선의 대답입니다
디지털 환상

시도 할 때, 나는 다음을받습니다 :TypeError: children is not a function
Ryan Prentiss

6

나는 그것을 사용하여 작동하도록 위의 허용 대답을 해결하는 데 필요한 대신 포인터를. 지도 기능의 범위 내에서이 없었어요 해봐요 함수를 정의했다.

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

업데이트 :이 수정은 ECMAScript 5 용이며 ES6에서는 var that = this 가 필요하지 않습니다.


13
또는 그냥 사용하십시오bind()
plus-

1
또는 어휘 범위에 바인딩하는 화살표 기능을 사용하면 대답을 업데이트했습니다.
Dominic

만약에하면 doSomething같은 개체를했다 doSomething: function(obj) { console.log(obj) }당신이 전화 줄과 아동에 this.props.doSomething(obj)로그 아웃"obj"
conor909

4
@ plus- 나는 이것이 오래되었다는 것을 알고 있지만 여기서 bind를 사용하는 것은 끔찍한 아이디어입니다. bind는 컨텍스트를 새로운 것에 바인딩하는 새로운 함수를 만듭니다. 기본적으로 apply메소드를 호출하는 함수 입니다. 사용하여 bind()렌더링 기능으로하는 새로운 기능을 렌더링 메소드가 호출 될 때마다 생성됩니다.
Bamieh

6

한 명 이상의 자녀를 고려한보다 깨끗한 방법

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

이것은 나를 위해 작동하지 않으며 오류가 발생합니다 : 자녀가 정의되지 않았습니다.
Deelux

@Deelux이 아이들 대신에 this.props.children
마틴 도슨

이것은에서 자녀를 자신의 자녀로 전달합니다 this.props. 일반적으로 나는 전체 소품이 아닌 특정 소품으로 복제하는 것이 좋습니다.
Andy

통과 {...this.props}가 효과가 없었습니다. {...child.props}올바른 방법 입니까?
Felipe Augusto

기능적 구성 요소 :React.Children.map(children, child => React.cloneElement(child, props))
vsync

5

텍스트 문자열과 같이 리 액티브 구성 요소 가 아닌 자식을 갖는 문제에 대한 답변은 없습니다 . 해결 방법은 다음과 같습니다.

// 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>

}

5

더 이상 필요하지 않습니다 {this.props.children}. 이제 평소와 같이 renderin을 사용하여 자식 구성 요소를 감싸고 Route소품을 전달할 수 있습니다.

<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>

2
렌더 소품은 이제 React에서 표준 ( reactjs.org/docs/render-props.html ) 이며이 질문에 대한 새로운 답변으로 고려할 가치가 있습니다.
Ian Danforth

19
이것이 어떻게 질문에 대한 답입니까?
Maximo Dominguez

4

Parent.jsx :

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

Child.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)}/>
);

그리고 main.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('...')
);

여기 예를 참조하십시오 : https://plnkr.co/edit/jJHQECrKRrtKlKYRpIWl?p=preview



4

소품 을 여러 개 전달 하려는 경우 React.Children.map을 사용하여 다음과 같이 할 수 있습니다.

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

    return (
        <div>
            { updatedChildren }
        </div>
    );
}

구성 요소에 자식이 하나 뿐인 경우 매핑 할 필요가 없으며 곧바로 cloneElement를 사용할 수 있습니다.

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

3

의 문서에 따르면 cloneElement()

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

element를 시작점으로 사용하여 새로운 React 요소를 복제하고 반환합니다. 결과 요소는 원래 요소의 소품을 새 소품과 얕게 병합합니다. 새 어린이는 기존 어린이를 대체합니다. 원래 요소의 키와 참조는 유지됩니다.

React.cloneElement() 거의 다음과 같습니다.

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

그러나 심판을 유지합니다. 이것은 당신이 그것에 심판을 가진 아이를 얻는다면, 실수로 조상으로부터 아이를 훔치지 않을 것임을 의미합니다. 새 요소에 동일한 참조가 첨부됩니다.

따라서 cloneElement는 자녀에게 맞춤형 소품을 제공하는 데 사용하는 것입니다. 그러나 구성 요소에 여러 하위가있을 수 있으며이를 반복해야합니다. 다른 답변에서 제안하는 것은을 사용하여 매핑하는 것 React.Children.map입니다. 그러나 요소 추가 키와 추가 키를 접두사로 변경하는 React.Children.map것과는 다릅니다 . 자세한 내용은이 질문을 확인하십시오. React.Children.map 내의 React.cloneElement로 인해 요소 키가 변경됩니다React.cloneElement.$

그것을 피하려면 대신 다음 forEach과 같은 기능을 수행 해야합니다

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

}

2

@and_rest 답변 외에도 자녀를 복제하고 클래스를 추가하는 방법입니다.

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

2

렌더링 소품 이이 시나리오를 처리하는 적절한 방법이라고 생각합니다.

부모 코드를 리팩토링하여 다음과 같이 보이게하여 부모가 자식 구성 요소에 사용되는 필수 소품을 제공하게합니다.

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

  return children({ doSomething })
}

그런 다음 자식 구성 요소에서 다음과 같이 부모가 제공 한 기능에 액세스 할 수 있습니다.

class Child extends React {

  onClick() => { this.props.doSomething }

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

}

이제 fianl 구조는 다음과 같습니다.

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

부모가 다른 클래스 구성 요소의 텍스트 영역 인 {children}의 래퍼 인 경우 어떻게합니까?
Adebayo

2

방법 1-자식 복제

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

   return <div>{childrenWithAdjustedProps }</div>
}

방법 2-컴포저 블 컨텍스트 사용

컨텍스트를 사용하면 사이에있는 구성 요소를 통해 소품으로 명시 적으로 전달하지 않고 깊은 하위 구성 요소에 소품을 전달할 수 있습니다.

컨텍스트에는 다음과 같은 단점이 있습니다.

  1. 소품을 통해 데이터가 규칙적으로 흐르지 않습니다.
  2. 컨텍스트를 사용하면 소비자와 공급자간에 계약이 생성됩니다. 구성 요소 재사용에 필요한 요구 사항을 이해하고 복제하기가 더 어려울 수 있습니다.

컴포저 블 컨텍스트 사용

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

조금 늦었지만 표기법을 설명해 주 {children}:{children:ReactNode}시겠습니까?
camille

@camille, 그것은 Typescript 일입니다. 지금 보면 Javascript로 대답하고 Typescript를 작성하더라도 다르게 할 것입니다. 나중에 편집 할 수 있습니다.
벤 잉어

1
@camille, 기본적으로 그것은 키를 가진 값이 "children"유형 이라는 것을 의미합니다ReactNode
Ben Carp

1

가장 매끄러운 방법은 다음과 같습니다.

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

5
이것으로 this.props.children을 자식의 this.props.children에 복사하지 않습니까? 그리고 실제로 아이를 자기 자신으로 복사합니까?
Arshabh Agarwal

1

자식 요소가 하나 인 사람은 그렇게해야합니다.

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

0

이것이 당신이 요구 한 것입니까?

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

4
아니, 래퍼의 내용을 특정 내용으로 제한하고 싶지 않습니다.
plus-

0

어떤 이유로 React.children이 나를 위해 작동하지 않았습니다. 이것이 나를 위해 일한 것입니다.

아이에게 수업을 추가하고 싶었습니다. 소품 변경과 유사

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

 return <div>{newChildren}</div>;

여기서 트릭은 React.cloneElement 입니다. 비슷한 방식으로 소품을 전달할 수 있습니다


0

렌더링 소품 은이 문제에 대한 가장 정확한 접근법입니다. 자식 소품으로 자식 구성 요소를 부모 구성 요소에 전달하는 대신 부모가 자식 구성 요소를 수동으로 렌더링하도록하십시오. 렌더 는 반응하는 내장 소품으로, 기능 매개 변수를 사용합니다. 이 기능을 사용하면 부모 구성 요소가 사용자 정의 매개 변수를 사용하여 원하는 것을 렌더링 할 수 있습니다. 기본적으로 그것은 자식 소품과 같은 일을하지만 더 사용자 정의 할 수 있습니다.

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

코드 펜의 예


0

기능적 구성 요소를 사용할 때 종종 TypeError: Cannot add property myNewProp, object is not extensible 때에 새 특성을 설정하려고 할 때 오류가 발생합니다 props.children. 소품을 복제 한 다음 새로운 소품으로 어린이 자체를 복제하면이 문제를 해결할 수 있습니다.

const MyParentComponent = (props) => {
  return (
    <div className='whatever'>
      {props.children.map((child) => {
        const newProps = { ...child.props }
        // set new props here on newProps
        newProps.myNewProp = 'something'
        const preparedChild = { ...child, props: newProps }
        return preparedChild
      })}
    </div>
  )
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.