React에서 부모의 상태를 업데이트하는 방법은 무엇입니까?


351

내 구조는 다음과 같습니다.

Component 1  

 - |- Component 2


 - - |- Component 4


 - - -  |- Component 5  

Component 3

구성 요소 3은 구성 요소 5의 상태에 따라 일부 데이터를 표시해야합니다. 소품은 변경할 수 없으므로 단순히 구성 요소 1의 상태를 저장 한 다음 전달할 수 없습니다. 그리고 예, 나는 redux에 대해 읽었지만 그것을 사용하고 싶지 않습니다. 반응만으로 해결할 수 있기를 바랍니다. 내가 잘못?


20
매우 쉬운 방법 : 속성을 통해 parent-setState-Function을 자식 구성 요소로 전달하십시오. <MyChildComponent setState = {p => {this.setState (p)}} /> 자식 구성 요소에서 this.props를 통해 호출하십시오. setState ({myObj, ...});
Marcel Ennix

@MarcelEnnix, 귀하의 의견은 시간을 절약합니다. 감사.
Dinith Minura

<MyChildComponent setState={(s,c)=>{this.setState(s, c)}} />이 해킹을 사용하려면 콜백을 지원해야합니다.
Barkermn01

4
부모의 상태를 설정하기 위해 콜백을 전달하는 것은 유지 관리 문제로 이어질 수있는 실제로 나쁜 습관입니다. 캡슐화가 끊어지고 구성 요소 2 4와 5가 1에 단단히 연결됩니다.이 경로를 따라 가면 이러한 하위 구성 요소를 다른 곳에서 재사용 할 수 없습니다. 특정 소품을 가지고 있으면 하위 구성 요소가 발생할 때마다 이벤트를 트리거 할 수 있으므로 상위 구성 요소가 해당 이벤트를 올바르게 처리합니다.
Pato Loco

@MarcelEnnix, 왜 중괄호 주위에 this.setState(p)? 나는 그들없이 시도했고 작동하는 것 같습니다 (React를
처음 접합니다

답변:


679

자녀-부모 의사 소통을 위해 다음과 같이 부모에서 자녀로 상태를 설정하는 함수를 전달해야합니다.

class Parent extends React.Component {
  constructor(props) {
    super(props)

    this.handler = this.handler.bind(this)
  }

  handler() {
    this.setState({
      someVar: 'some value'
    })
  }

  render() {
    return <Child handler = {this.handler} />
  }
}

class Child extends React.Component {
  render() {
    return <Button onClick = {this.props.handler}/ >
  }
}

이런 식으로 자식은 소품과 함께 전달 된 함수의 호출로 부모의 상태를 업데이트 할 수 있습니다.

그러나 구성 요소 5와 3은 관련이 없기 때문에 구성 요소의 구조를 재고해야합니다.

가능한 해결책 중 하나는 컴포넌트 1과 3의 상태를 모두 포함하는 상위 레벨 컴포넌트로 랩핑하는 것입니다.이 컴포넌트는 소품을 통해 하위 레벨 상태를 설정합니다.


6
왜 상태를 설정하는 핸들러 함수뿐만 아니라 this.handler = this.handler.bind (this)가 필요한가?
chemook78

35
ES6 React 클래스의 @ chemook78 메소드는 클래스에 자동 바인딩되지 않습니다. 따라서 this.handler = this.handler.bind(this)생성자를 추가하지 않으면 함수 this내부 handler에서 클래스가 아닌 함수 클로저를 참조합니다. 생성자에서 모든 함수를 바인딩하지 않으려면 화살표 함수를 사용하여이를 처리하는 두 가지 방법이 더 있습니다. 클릭 핸들러를로 쓰거나 "화살표 함수"onClick={()=> this.setState(...)}
Ivan

1
다음은 이에 대한 예입니다. plnkr.co/edit/tGWecotmktae8zjS5yEr?p=preview
Tamb

5
이것이 모두 의미가있는 이유는 무엇입니까? e.preventDefault? 그리고 jquery가 필요합니까?
빈센트 Buscarello

1
빠른 질문, 이것이 어린이 내에서 지방 국가의 할당을 허용하지 않습니까?
ThisGuyCant17 년

50

자식에서 부모 구성 요소로 onClick 함수 인수를 전달하는 다음 작업 솔루션을 찾았습니다.

메소드를 전달하는 버전 ()

//ChildB component
class ChildB extends React.Component {

    render() {

        var handleToUpdate  =   this.props.handleToUpdate;
        return (<div><button onClick={() => handleToUpdate('someVar')}>
            Push me
          </button>
        </div>)
    }
}

//ParentA component
class ParentA extends React.Component {

    constructor(props) {
        super(props);
        var handleToUpdate  = this.handleToUpdate.bind(this);
        var arg1 = '';
    }

    handleToUpdate(someArg){
            alert('We pass argument from Child to Parent: ' + someArg);
            this.setState({arg1:someArg});
    }

    render() {
        var handleToUpdate  =   this.handleToUpdate;

        return (<div>
                    <ChildB handleToUpdate = {handleToUpdate.bind(this)} /></div>)
    }
}

if(document.querySelector("#demo")){
    ReactDOM.render(
        <ParentA />,
        document.querySelector("#demo")
    );
}

JSFIDDLE을보십시오

화살표 함수를 전달하는 버전

//ChildB component
class ChildB extends React.Component {

    render() {

        var handleToUpdate  =   this.props.handleToUpdate;
        return (<div>
          <button onClick={() => handleToUpdate('someVar')}>
            Push me
          </button>
        </div>)
    }
}

//ParentA component
class ParentA extends React.Component { 
    constructor(props) {
        super(props);
    }

    handleToUpdate = (someArg) => {
            alert('We pass argument from Child to Parent: ' + someArg);
    }

    render() {
        return (<div>
            <ChildB handleToUpdate = {this.handleToUpdate} /></div>)
    }
}

if(document.querySelector("#demo")){
    ReactDOM.render(
        <ParentA />,
        document.querySelector("#demo")
    );
}

JSFIDDLE을보십시오


이거 좋다! 이 부분을 설명해 주 <ChildB handleToUpdate = {handleToUpdate.bind(this)} />시겠습니까? 왜 다시 바인딩해야합니까?
Dane

@Dane- this자식의 내부에서 호출 될 때 자식 this의 상태가 아닌 부모의 상태를 나타내도록 컨텍스트를 부모로 바인딩해야합니다 . 이것은 최고의 마감입니다!
Casey

@Casey 그러나 생성자에서 그렇게하지 않습니까? 그리고 충분하지 않습니까 ??
Dane

당신 말이 맞아요! 나는 그것을 놓쳤다. 예, 생성자에서 이미 수행 한 경우 계속 진행할 수 있습니다.
Casey

당신은 전설의 친구입니다! 이렇게하면 상태 교환을 처리하기 위해 부모 구성 요소를 만들 필요없이 구성 요소를 자체적으로 안전하게 유지할 수 있습니다.
adamj

13

기본적으로 화살표 기능을 사용하여 내 문제에 대한 아이디어를 제공하고 하위 구성 요소에서 매개 변수를 전달한 것에 대한 가장 큰 대답을 고맙게 생각합니다.

 class Parent extends React.Component {
  constructor(props) {
    super(props)
    // without bind, replaced by arrow func below
  }

  handler = (val) => {
    this.setState({
      someVar: val
    })
  }

  render() {
    return <Child handler = {this.handler} />
  }
}

class Child extends React.Component {
  render() {
    return <Button onClick = {() => this.props.handler('the passing value')}/ >
  }
}

그것이 누군가를 돕기를 바랍니다.


직접 통화를 통한 화살표 기능의 특별한 점은 무엇입니까?
Ashish Kamble

@ this화살표 함수는 부모의 컨텍스트 (예 : Parent클래스)를 나타냅니다.
CPHPython 2016 년

이것은 중복 답변입니다. 허용 된 답변에 의견을 추가하고이 실험 기능에 대해 언급 하여 수업에서 화살표 기능을 사용할 수 있습니다.
Arashsoft

10

나는 함수를 전달하는 것에 대한 대답, 매우 편리한 기술을 좋아합니다.

반면 플럭스 와 마찬가지로 pub / sub 또는 변형 디스패처를 사용하여이를 달성 할 수도 있습니다 . 이론은 매우 간단합니다. 컴포넌트 5가 컴포넌트 3이 수신하는 메시지를 발송하도록합니다. 그런 다음 구성 요소 3은 상태를 업데이트하여 다시 렌더링을 트리거합니다. 이를 위해서는 관점에 따라 반 패턴 일 수도 있고 아닐 수도있는 상태 저장 구성 요소가 필요합니다. 나는 개인적으로 그들에 대항하고 있으며 다른 무언가가 파견을 듣고 있으며 하향식에서 상태를 변경하고 싶습니다 (Redux는 이것을하지만 추가 용어를 추가합니다).

import { Dispatcher } from flux
import { Component } from React

const dispatcher = new Dispatcher()

// Component 3
// Some methods, such as constructor, omitted for brevity
class StatefulParent extends Component {
  state = {
    text: 'foo'
  } 

  componentDidMount() {
    dispatcher.register( dispatch => {
      if ( dispatch.type === 'change' ) {
        this.setState({ text: 'bar' })
      }
    }
  }

  render() {
    return <h1>{ this.state.text }</h1>
  }
}

// Click handler
const onClick = event => {
  dispatcher.dispatch({
    type: 'change'
  })
}

// Component 5 in your example
const StatelessChild = props => {
  return <button onClick={ onClick }>Click me</button> 
}

Flux가 포함 된 디스패처 번들은 매우 간단합니다. 디스패치의 내용을 전달하여 디스패치가 발생할 때 콜백을 등록하고 호출합니다 (위의 간결한 예제에는 payload메시지 ID가 없음). 당신이 더 합리적이라면 전통적인 펍 / 서브 (예를 들어, 이벤트에서 EventEmitter를 사용하거나 다른 버전으로)에 이것을 쉽게 조정할 수 있습니다.


공식 Reacts ( facebook.github.io/react/docs/tutorial.html ) 와 같이 브라우저에서 내 Reacts 구성 요소가 "실행 중"입니다.
browserify에

2
내가 사용한 구문은 ES2016 모듈 구문으로 변환이 필요합니다 ( Babel을 사용 하지만, 다른 것들도 있습니다 . babelify 변환을 browserify 와 함께 사용할 수 있습니다).var Dispatcher = require( 'flux' ).Dispatcher
Matt Styles

8

param을 사용하여 자식에서 부모 구성 요소로 onClick 함수 인수를 전달하는 다음 작업 솔루션을 찾았습니다.

부모 클래스 :

class Parent extends React.Component {
constructor(props) {
    super(props)

    // Bind the this context to the handler function
    this.handler = this.handler.bind(this);

    // Set some state
    this.state = {
        messageShown: false
    };
}

// This method will be sent to the child component
handler(param1) {
console.log(param1);
    this.setState({
        messageShown: true
    });
}

// Render the child component and set the action property with the handler as value
render() {
    return <Child action={this.handler} />
}}

어린이 수업 :

class Child extends React.Component {
render() {
    return (
        <div>
            {/* The button will execute the handler function set by the parent component */}
            <Button onClick={this.props.action.bind(this,param1)} />
        </div>
    )
} }

2
누구나 수용 가능한 솔루션인지 여부를 알 수 있습니까 (특히 제안 된 매개 변수 전달에 관심이 있음).
ilans

param1다만 콘솔에 표시되는 것은 항상 양수인 할당하지true
인 Ashish Kamble

나는 솔루션의 품질에 대해 말할 수 없지만 이것은 성공적으로 나에게 매개 변수를 전달합니다.
제임스

6

어떤 수준에서든 자녀와 부모 사이의 의사 소통이 필요할 때마다 context를 사용하는 것이 좋습니다 . 상위 컴포넌트에서 다음과 같이 하위에서 호출 할 수있는 컨텍스트를 정의하십시오.

사례 구성 요소 3의 상위 구성 요소

static childContextTypes = {
        parentMethod: React.PropTypes.func.isRequired
      };

       getChildContext() {
        return {
          parentMethod: (parameter_from_child) => this.parentMethod(parameter_from_child)
        };
      }

parentMethod(parameter_from_child){
// update the state with parameter_from_child
}

이제 하위 구성 요소 (귀하의 경우 구성 요소 5) 에서이 구성 요소에 부모의 컨텍스트를 사용하고 싶다고 알려주십시오.

 static contextTypes = {
       parentMethod: React.PropTypes.func.isRequired
     };
render(){
    return(
      <TouchableHighlight
        onPress={() =>this.context.parentMethod(new_state_value)}
         underlayColor='gray' >   

            <Text> update state in parent component </Text>              

      </TouchableHighlight>
)}

repo 에서 데모 프로젝트를 찾을 수 있습니다


나는 당신이 그것에 대해 자세한 내용을 설명 할 수있는,이 대답을 이해할 수 캔트
인 Ashish Kamble

5

react가 단방향 데이터 흐름을 촉진함에 따라 부모에서 자식으로 만 데이터를 전달할 수 있지만 "자식 구성 요소"에서 무언가가 발생할 때 부모를 자체적으로 업데이트하기 위해 일반적으로 "콜백 함수"를 사용합니다.

부모에 정의 된 함수를 자식에 "props"로 전달하고 해당 함수를 자식 구성 요소에서 트리거하는 자식 함수에서 호출합니다.


class Parent extends React.Component {
  handler = (Value_Passed_From_SubChild) => {
    console.log("Parent got triggered when a grandchild button was clicked");
    console.log("Parent->Child->SubChild");
    console.log(Value_Passed_From_SubChild);
  }
  render() {
    return <Child handler = {this.handler} />
  }
}
class Child extends React.Component {
  render() {
    return <SubChild handler = {this.props.handler}/ >
  }
}
class SubChild extends React.Component { 
  constructor(props){
   super(props);
   this.state = {
      somethingImp : [1,2,3,4]
   }
  }
  render() {
     return <button onClick = {this.props.handler(this.state.somethingImp)}>Clickme<button/>
  }
}
React.render(<Parent />,document.getElementById('app'));

 HTML
 ----
 <div id="app"></div>

이 예에서는 함수를 직계 Child에 전달하여 SubChild-> Child-> Parent에서 데이터를 전달할 수 있습니다.


4

이 페이지에서 최고 등급의 답변을 여러 번 사용했지만 React를 배우는 동안 소품 내부의 바인딩과 인라인 기능없이이를 수행하는 더 좋은 방법을 찾았습니다.

여기를보세요 :

class Parent extends React.Component {

  constructor() {
    super();
    this.state={
      someVar: value
    }
  }

  handleChange=(someValue)=>{
    this.setState({someVar: someValue})
  }

  render() {
    return <Child handler={this.handleChange} />
  }

}

export const Child = ({handler}) => {
  return <Button onClick={handler} />
}

키는 화살표 기능입니다.

handleChange=(someValue)=>{
  this.setState({someVar: someValue})
}

자세한 내용은 여기를 참조 하십시오 . 희망이 이것이 누군가에게 유용 할 것입니다 =)


이것은 나에게 훨씬 더 의미가 있습니다. 감사합니다!
Brett Rowberry

3

-ParentComponent를 만들고 handleInputChange 메소드를 사용하여 ParentComponent 상태를 업데이트 할 수 있습니다. ChildComponent를 임포트하면 부모에서 자식 컴포넌트로 두 개의 props를 전달합니다.

import React, { Component } from 'react';
import ChildComponent from './ChildComponent';

class ParentComponent extends Component {
  constructor(props) {
    super(props);
    this.handleInputChange = this.handleInputChange.bind(this);
    this.state = {
      count: '',
    };
  }

  handleInputChange(e) {
    const { value, name } = e.target;
    this.setState({ [name]: value });
  }

  render() {
    const { count } = this.state;
    return (
      <ChildComponent count={count} handleInputChange={this.handleInputChange} />
    );
  }
}
  • 이제 ChildComponent 파일을 만들고 ChildComponent.jsx로 저장합니다. 하위 구성 요소에 상태가 없기 때문에이 구성 요소는 상태 비 저장입니다. 소품 유형 검사에는 prop-types 라이브러리를 사용합니다.

    import React from 'react';
    import { func, number } from 'prop-types';
    
    const ChildComponent = ({ handleInputChange, count }) => (
      <input onChange={handleInputChange} value={count} name="count" />
    );
    
    ChildComponent.propTypes = {
      count: number,
      handleInputChange: func.isRequired,
    };
    
    ChildComponent.defaultProps = {
      count: 0,
    };
    
    export default ChildComponent;

자녀에게 부모의 소도구에 영향을 미치는 자녀가있을 때 어떻게 작동합니까?
Bobort

3

이 동일한 시나리오가 모든 곳에 퍼져 있지 않은 경우, 특히 상태 관리 라이브러리가 도입하는 모든 오버 헤드를 도입하지 않으려는 경우 React의 컨텍스트를 사용할 수 있습니다. 또한 배우기가 더 쉽습니다. 그러나 조심해서 사용하면 잘못된 코드를 작성할 수 있습니다. 기본적으로 컨테이너 구성 요소를 정의하면 (그 상태를 유지하고 유지할 것입니다) 모든 구성 요소가 해당 데이터 조각을 자식으로 쓰거나 읽는 데 관심이 있습니다 (직접 자식은 아님)

https://reactjs.org/docs/context.html

대신 일반 반응을 올바르게 사용할 수도 있습니다.

<Component5 onSomethingHappenedIn5={this.props.doSomethingAbout5} />

컴포넌트 1까지 doSomethingAbout5를 전달하십시오.

    <Component1>
        <Component2 onSomethingHappenedIn5={somethingAbout5 => this.setState({somethingAbout5})}/>
        <Component5 propThatDependsOn5={this.state.somethingAbout5}/>
    <Component1/>

이것이 일반적인 문제라면 응용 프로그램의 전체 상태를 다른 곳으로 옮기는 것을 생각해야합니다. 몇 가지 옵션이 있으며 가장 일반적인 옵션은 다음과 같습니다.

https://redux.js.org/

https://facebook.github.io/flux/

기본적으로 구성 요소에서 응용 프로그램 상태를 관리하는 대신 상태가 업데이트 될 때 명령을 보냅니다. 구성 요소는이 컨테이너에서 상태를 가져와 모든 데이터가 중앙 집중화됩니다. 이것은 더 이상 로컬 상태를 사용할 수 없다는 것을 의미하지는 않지만 더 고급 주제입니다.


2

따라서 상위 구성 요소를 업데이트하려는 경우

 class ParentComponent extends React.Component {
        constructor(props){
            super(props);
            this.state = {
               page:0
            }
        }

        handler(val){
            console.log(val) // 1
        }

        render(){
          return (
              <ChildComponent onChange={this.handler} />
           )
       }
   }


class ChildComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
             page:1
        };
    }

    someMethod = (page) => {
        this.setState({ page: page });
        this.props.onChange(page)
    }

    render() {
        return (
       <Button
            onClick={() => this.someMethod()} 
       > Click
        </Button>
      )
   }
}

여기서 onChange는 "handler"메소드가 인스턴스에 바인딩 된 속성입니다. props 인수에서 onChange 속성을 통해 수신하도록 메소드 핸들러를 Child 클래스 컴포넌트로 전달했습니다.

onChange 속성은 다음과 같이 props 객체에 설정됩니다.

props ={
onChange : this.handler
}

자식 구성 요소로 전달

따라서 Child 컴포넌트는 props.onChange와 같은 props 객체의 name 값에 액세스 할 수 있습니다.

렌더링 소품을 사용하여 수행됩니다.

이제 Child 컴포넌트에는 props 인수 객체에서 onChnge를 통해 전달 된 핸들러 메소드를 호출하기 위해 onclick 이벤트가 설정된 "Click"버튼이 있습니다. 이제 Child의 this.props.onChange는 Parent 클래스 Reference 및 credits : Bits and Pieces에 출력 메소드를 보유합니다 .


죄송합니다. 지연에 대해, 여기 onChange는 "handler"메소드가 인스턴스에 바인딩 된 속성입니다. props 인수에서 onChange 속성을 통해 수신하도록 메소드 핸들러를 Child 클래스 컴포넌트로 전달했습니다. onChange 속성은 props = {onChange : this.handler}와 같은 props 객체에 설정되며 자식 구성 요소에 전달되므로 Child 구성 요소는 props.onChange와 같은 props 개체의 이름 값에 액세스 할 수 있습니다. 렌더 소품 사용. 참조 및 크레딧 : [ blog.bitsrc.io/…
Preetham NT

0

이것이 내가하는 방식입니다.

type ParentProps = {}
type ParentState = { someValue: number }
class Parent extends React.Component<ParentProps, ParentState> {
    constructor(props: ParentProps) {
        super(props)
        this.state = { someValue: 0 }

        this.handleChange = this.handleChange.bind(this)
    }

    handleChange(value: number) {
        this.setState({...this.state, someValue: value})
    }

    render() {
        return <div>
            <Child changeFunction={this.handleChange} defaultValue={this.state.someValue} />
            <p>Value: {this.state.someValue}</p>
        </div>
    }
}

type ChildProps = { defaultValue: number, changeFunction: (value: number) => void}
type ChildState = { anotherValue: number }
class Child extends React.Component<ChildProps, ChildState> {
    constructor(props: ChildProps) {
        super(props)
        this.state = { anotherValue: this.props.defaultValue }

        this.handleChange = this.handleChange.bind(this)
    }

    handleChange(value: number) {
        this.setState({...this.state, anotherValue: value})
        this.props.changeFunction(value)
    }

    render() {
        return <div>
            <input onChange={event => this.handleChange(Number(event.target.value))} type='number' value={this.state.anotherValue}/>
        </div>
    }
}

0

위에 주어진 대부분의 답변은 React.Component 기반 디자인에 대한 것입니다. useState최근 React 라이브러리 업그레이드에서 사용하는 경우 다음 답변 을 따르십시오.


-3
<Footer 
  action={()=>this.setState({showChart: true})}
/>

<footer className="row">
    <button type="button" onClick={this.props.action}>Edit</button>
  {console.log(this.props)}
</footer>

Try this example to write inline setState, it avoids creating another function.

성능 문제가 발생합니다 : stackoverflow.com/q/36677733/3328979
Arashsoft
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.