React/React 문법

[React]자식 컴포넌트가 부모 컴포넌트의 state 변경

DevStory 2021. 7. 23.

자식 컴포넌트가 부모 컴포넌트의 state를 변경

설명할 컴포넌트의 구조는 아래 사진과 같습니다.

컴포넌트의 역할
index : 최상위 컴포넌트 어떠한 동작도 기능도 존재하지 않음
App : View 컴포넌트와 ButtonComponent 컴포넌트에 전달하는 state를 관리하고 있음
NotWork : 어떠한 동작도 기능도 존재하지 않음
ButtonComponent : 버튼 클릭 시 App 컴포넌트의 state에 데이터를 추가함
View : App 컴포넌트의 state를 화면에 출력함

※ CodeSandBox에서 Button.js 파일을 만들 수가 없어서 ButtonComponent로 생성하였습니다. 큰 의미는 없습니다.


샘플


App의 컴포넌트의 state를 변경하는 함수를 ButtonComponent 컴포넌트에 전달

자식 컴포넌트(ButtonComponent)가 부모 컴포넌트(App)의 state를 갱신하거나 변경하는 경우 부모 컴포넌트에서 state를 변경하는 함수를 생성하여 자식 컴포넌트에게 전달 해야 합니다.

부모 컴포넌트 : App
App의 state를 변경하는 자식 컴포넌트 :  ButtonComponent

 

부모 컴포넌트(App)의 코드

export default class App extends Component {
  constructor(props) {
    super(props);
    // state를 정의합니다.
    this.state = {
      data: data
    };
  }

  // this.state.data에 데이터를 추가하는 함수를 생성합니다.
  addBook = (book) => {
    const newList = [
      ...this.state.data,
      {
        Book: book
      }
    ];
    this.setState({ data: newList });
  };

  render() {
    return (
      <div className="App">
        <h1>부모 -> 자식 값 전달 테스트</h1>
        <NotWork />
        {/* this.state.data에 데이터를 추가하는 함수를 전달합니다 */}
        <ButtonComponent addBook={this.addBook} />
        <View data={this.state.data} />
      </div>
    );
  }
}

순서

1. 부모 컴포넌트에서 state를 정의합니다.

this.state = {
  data: data
};

2. 부모 컴포넌트에서 this.state에 데이터를 추가하는 함수를 생성합니다.

스프레드 연산자(...)로 기존의 데이터를 유지하고 맨 마지막에 데이터를 추가합니다.

addBook = (book) => {
  const newList = [
    ...this.state.data,
    {
      Book: book
    }
  ];
  this.setState({ data: newList });
};

3. ButtonComponent에 2번 과정에서 생성한 함수를 전달합니다.

<ButtonComponent addBook={this.addBook} />

 

자식 컴포넌트(ButtonComponent)의 코드

export class ButtonComponent extends Component {
  constructor(props) {
    super(props);

    this.handleButtonClick = this.handleButtonClick.bind(this);
  }

  handleButtonClick() {
    this.props.addBook("버튼클릭했다.");
  }

  render() {
    return (
      <div>
        <button type="button" onClick={this.handleButtonClick}>
          부모 컴포넌트의 state를 변경합니다.
        </button>
      </div>
    );
  }
}

순서

1. 이벤트가 발생했을 경우 부모 컴포넌트에서 전달받은 함수를 호출합니다.

handleButtonClick() {
  this.props.addBook("버튼클릭했다.");
}

부모 컴포넌트의 state가 변경되면 자식 컴포넌트들은 re-render 됩니다.

NotWork 컴포넌트는 부모 컴포넌트(App)로부터 어떠한 state를 전달받지도 않고 내부적으로 기능 및 동작도 없습니다.

단순히 엘리먼트를 render()하는 용도로 사용되고 있습니다.

 

NotWork 컴포넌트의 코드

export class NotWork extends Component {
  render() {
    console.log(`NotWork Component에서 render()를 호출`);
    return (
      <div>
        <h1>NotWork Component는 어떠한 동작도 하지 않습니다.</h1>
      </div>
    );
  }
}

 

순서

1. 최초 화면 실행 시 

2. 버튼 클릭

NotWork 컴포넌트는 부모 컴포넌트의 state가 변경되어 강제로 re-render 됩니다. 콘솔 창에서 확인이 가능합니다.


마무리

자식 컴포넌트가 부모 컴포넌트의 state를 변경하는 코드를 작성하면서 React에 대한 환상이 깨졌습니다. "부모 컴포넌트와 연결된 모든 자식 컴포넌트들이 re-render 되는 것이 좋은 방식인가...?"라는 생각이 들었습니다.

 

이러한 문제점을 인지를 했는지 FacebookRecoil이라는 라이브러리를 개발하였습니다. Recoil 라이브러리는 모든 자식 컴포넌트를 re-render 하는 것이 아니라 특정 자식 컴포넌트만 re-render 해줄 수 있게 하는 라이브러리입니다.

 

아직 불안정한 라이브러리라고 평가를 받고 있지만, Facebook이 지속적으로 React를 개선한다는 것은 확실하다고 할 수 있겠네요. 추후 Recoil 라이브러리 사용법도 포스팅하도록 하겠습니다.

반응형

댓글