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

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

<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}래퍼 구성 요소를 정의하는 데 사용할 때마다 모든 자식에게 일부 속성을 어떻게 전달합니까?



답변

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

당신은 사용할 수 있습니다 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/


답변

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

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


답변

이 시도

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

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


답변

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

다른 답변 모두보기

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

컨텍스트는 현재 인증 된 사용자, 테마 또는 선호 언어와 같은 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


답변

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

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


답변

을 사용할 수 있습니다 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를 사용하는 것을 고려할 수있는 좋은 기회입니다. 실제로 제거하기 전에 사용 중단 알림이 포함 된 릴리스를 제공하므로 즉각적인 조치가 필요하지 않습니다.

여기에


답변

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

예:

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

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