ReactJS : 자식 구성 요소 내부 부모의 setState


90

자식 구성 요소의 부모에서 setState를 수행하는 데 권장되는 패턴은 무엇입니까?

var Todos = React.createClass({
  getInitialState: function() {
    return {
      todos: [
        "I am done",
        "I am not done"
      ]
    }
  },

  render: function() {
    var todos = this.state.todos.map(function(todo) {
      return <div>{todo}</div>;
    });

    return <div>
      <h3>Todo(s)</h3>
      {todos}
      <TodoForm />
    </div>;
  }
});

var TodoForm = React.createClass({
  getInitialState: function() {
    return {
      todoInput: ""
    }
  },

  handleOnChange: function(e) {
    e.preventDefault();
    this.setState({todoInput: e.target.value});
  },

  handleClick: function(e) {
    e.preventDefault();
    //add the new todo item
  },

  render: function() {
    return <div>
      <br />
      <input type="text" value={this.state.todoInput} onChange={this.handleOnChange} />
      <button onClick={this.handleClick}>Add Todo</button>
    </div>;
  }
});

React.render(<Todos />, document.body)

부모의 상태로 유지되는 할 일 항목 배열이 있습니다. 부모의 상태에 액세스하고 TodoFormhandleClick구성 요소 에서 새 할 일 항목을 추가하고 싶습니다 . 내 생각은 부모에 대해 setState를 수행하여 새로 추가 된 할일 항목을 렌더링하는 것입니다.


1
이것은 stackoverflow.com/questions/24147331/…에 도움이 됩니까?
Dhiraj

여기에 그냥 거 스팸 ... npmjs.com/package/react-event-observer
jujiyangasli

오류가 발생합니다setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the MyModal component.
Matt

마운트되지 않은 구성 요소에서 setState를 사용할 수 없다는 것과 동일한 오류가 발생합니다. 이에 대한 해결 방법이 있었습니까?
Kevin Burton

답변:


81

부모 addTodoItem에서 필요한 setState를 수행하는 함수를 만든 다음 해당 함수를 하위 구성 요소에 소품으로 전달할 수 있습니다.

var Todos = React.createClass({

  ...

  addTodoItem: function(todoItem) {
    this.setState(({ todos }) => ({ todos: { ...todos, todoItem } }));
  },

  render: function() {

    ...

    return <div>
      <h3>Todo(s)</h3>
      {todos}
      <TodoForm addTodoItem={this.addTodoItem} />
    </div>
  }
});

var TodoForm = React.createClass({
  handleClick: function(e) {
    e.preventDefault();
    this.props.addTodoItem(this.state.todoInput);
    this.setState({todoInput: ""});
  },

  ...

});

addTodoItemTodoForm의 handleClick에서 호출 할 수 있습니다 . 이것은 새로 추가 된 할일 항목을 렌더링 할 부모에 대한 setState를 수행합니다. 아이디어를 얻으시기 바랍니다.

여기 바이올린.


6
여기서 <<운영자 는 무엇을 this.state.todos << todoItem;합니까?
Gabriel Garrett

@zavtra 리틀 루비 혼란 I에 추측 가고
azium

7
this.state직접 변이하는 것은 나쁜 습관 입니다. 기능적 setState를 사용하는 것이 더 좋습니다. reactjs.org/docs/react-component.html#setstate
Rohmer

2
바이올린은 고장
헌터 넬슨에게

1
이 (업데이트 된) 솔루션은 React 후크를 사용하여 어떻게 구현 될까요?
ecoe

11

이것들은 모두 본질적으로 정확합니다. 기본적으로 권장하는 새로운 공식 반응 문서를 가리킬 것이라고 생각했습니다.

React 애플리케이션에서 변경되는 모든 데이터에 대한 단일 "진실 소스"가 있어야합니다. 일반적으로 상태는 렌더링에 필요한 구성 요소에 먼저 추가됩니다. 그런 다음 다른 구성 요소도 필요하면 가장 가까운 공통 조상으로 들어 올릴 수 있습니다. 서로 다른 구성 요소간에 상태를 동기화하는 대신 하향식 데이터 흐름에 의존해야합니다.

https://reactjs.org/docs/lifting-state-up.html을 참조 하십시오 . 이 페이지는 예제를 통해서도 작동합니다.


8

부모 구성 요소에 addTodo 함수를 만들고 해당 컨텍스트에 바인딩하고 자식 구성 요소에 전달하고 거기에서 호출 할 수 있습니다.

// in Todos
addTodo: function(newTodo) {
    // add todo
}

그런 다음 Todos.render에서 다음을 수행합니다.

<TodoForm addToDo={this.addTodo.bind(this)} />

TodoForm에서 이것을 호출하십시오.

this.props.addToDo(newTodo);

이것은 매우 유용했습니다. bind(this)함수를 전달할 때 수행 하지 않고 그러한 함수가 없다는 오류가 발생했습니다 this.setState is not a function.
pratpor

6

React Hook으로 상태를 유지하는 사람들을 위해 useState위의 제안을 수정하여 아래의 데모 슬라이더 앱을 만들었습니다. 데모 앱에서 자식 슬라이더 구성 요소는 부모의 상태를 유지합니다.

데모에서는 useEffect후크 도 사용합니다 . (그리고 덜 중요한 것은 useRef후크)

import React, { useState, useEffect, useCallback, useRef } from "react";

//the parent react component
function Parent() {

  // the parentState will be set by its child slider component
  const [parentState, setParentState] = useState(0);

  // make wrapper function to give child
  const wrapperSetParentState = useCallback(val => {
    setParentState(val);
  }, [setParentState]);

  return (
    <div style={{ margin: 30 }}>
      <Child
        parentState={parentState}
        parentStateSetter={wrapperSetParentState}
      />
      <div>Parent State: {parentState}</div>
    </div>
  );
};

//the child react component
function Child({parentStateSetter}) {
  const childRef = useRef();
  const [childState, setChildState] = useState(0);

  useEffect(() => {
    parentStateSetter(childState);
  }, [parentStateSetter, childState]);

  const onSliderChangeHandler = e => {
  //pass slider's event value to child's state
    setChildState(e.target.value);
  };

  return (
    <div>
      <input
        type="range"
        min="1"
        max="255"
        value={childState}
        ref={childRef}
        onChange={onSliderChangeHandler}
      ></input>
    </div>
  );
};

export default Parent;

이 앱을 create-react-app과 함께 사용하고 App.js의 모든 코드를 위 코드로 바꿀 수 있습니다.
NicoWheat

안녕하세요, 저는 반응이 처음이고 궁금합니다. 사용해야 useEffect합니까? 데이터를 부모 및 자식 상태 모두에 저장해야하는 이유는 무엇입니까?
538ROMEO

1
예제는 데이터를 부모와 자식 모두에 저장해야하는 이유를 보여주기위한 것이 아닙니다. 대부분의 경우에는 필요하지 않습니다. 그러나 자녀가 부모 상태를 설정해야하는 상황에 처해 있다면 이렇게 할 수 있습니다. useEffect는 부모 상태를 childState 변경의 효과로 설정하려는 경우 필요합니다.
NicoWheat

3
parentSetState={(obj) => { this.setState(obj) }}

4
이 코드가 질문에 답할 수 있지만 문제를 해결하는 방법 및 / 또는 이유에 대한 추가 컨텍스트를 제공하면 답변의 장기적인 가치가 향상됩니다.
Nic3500

2

하위 구성 요소에서 상위 구성 요소로 인수를 전달하는 다음과 같은 작동하고 간단한 솔루션을 찾았습니다.

//ChildExt component
class ChildExt extends React.Component {
    render() {
        var handleForUpdate =   this.props.handleForUpdate;
        return (<div><button onClick={() => handleForUpdate('someNewVar')}>Push me</button></div>
        )
    }
}

//Parent component
class ParentExt extends React.Component {   
    constructor(props) {
        super(props);
        var handleForUpdate = this.handleForUpdate.bind(this);
    }
    handleForUpdate(someArg){
            alert('We pass argument from Child to Parent: \n' + someArg);   
    }

    render() {
        var handleForUpdate =   this.handleForUpdate;    
        return (<div>
                    <ChildExt handleForUpdate = {handleForUpdate.bind(this)} /></div>)
    }
}

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

JSFIDDLE 좀 봐


0

클래스 구성 요소를 부모로 사용하는 경우 setState를 자식에게 전달하는 매우 간단한 방법 중 하나는 화살표 함수 내에서 전달하는 것입니다. 이것은 통과 할 수있는 호이스트 된 환경을 설정함에 따라 작동합니다.

class ClassComponent ... {

    modifyState = () =>{
        this.setState({...})   
    }
    render(){
          return <><ChildComponent parentStateModifier={modifyState} /></>
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.