ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [React.js] Stateful vs Stateless Components
    Front-End(Web)/React - 프레임워크(React, Next) 2020. 11. 29. 19:21
    반응형

    🤷 Component의 다른 분류방법

    우리는 컴포넌트의 형식에 따라, 클래스형 컴포넌트 & 함수형 컴포넌트로 분류해서 공부했다.

    이 둘의 가장 큰 차이는, 구문형식과 더불어 state의 사용가능 여부에 있었다. (클래스는 가능, 함수는 불가)

    이러한 단점의 보완을 위해, 함수형 컴포넌트에는 Hooks 기능이 추가되었다.

     

    반대로, 클래스형 컴포넌트라고 해서 반드시 state를 가지고 있는 것은 아니다.

    이에 따라, 컴포넌트를 stateful / stateless 두 종류로도 나누는 것 같다. 이에 대해 공부해보았다.


    📒 Stateless & Stateful Component

    Stateless 컴포넌트(Child)와 Stateful 컴포넌트(Parent)를 클래스형으로 각각 코드해보았다.

     

    //📂Child.js
    
    import React from 'react';
    
    export class Child extends React.Component {
      render () {
        return <h1>Hey, my name is {this.props.name}</h1>
      }
    }

    Child(stateless) 컴포넌트이다. props.name을 출력할 것이며, 사용되기 위해선 export 처리를 반드시 해야한다.

     

    //📂 Parent.js
    
    import React from 'react';
    import ReactDOM from 'react-dom'
    import { Child } from './Child'
    
    class Parent extends React.Component {
      constructor(props) {
        super(props);
        this.state = { name: 'Frarthur' }
      }
      render () {
        return <Child name={this.state.name}/>
      }
    }
    
    ReactDOM.render(
      <Parent />,
      document.getElementById('app')
    )

    Parent(stateful) 컴포넌트이다. 먼저, state 초기화를 위해 생성자 함수에 this.state를 정의하고, 이를 Child 컴포넌트를 통해 출력한다.

     

    이렇게 만드는 이유는, props와 state의 운용목적의 차이 때문이다.

    props, state 모두 정보를 동적으로 관리하지만, props는 다른 컴포넌트에서 수정가능하고, state는 자체 수정이 가능한 차이가 있다.

     

    그렇기 때문에, props는 상위 혹은 다른 컴포넌트에 의해 수정되어야 한다. (아래같은 자체 수정 불가!)

    import React from 'react';
    
    class Bad extends React.Component {
      render() {
        this.props.message = 'yo'; 		// No Change!!!!!!
        return <h1>{this.props.message}</h1>;
      }
    }

    📒 Update Parent Component(state) :  child -> parent

    Parent의 state는 Child의 요청으로 변경(업데이트)할 수 있다. Select Box 값 변경에 따라 <h1> 이름이 달라지는 코드를 작성했다.

     

    //📂 Parent.js
    
    import React from 'react';
    import ReactDOM from 'react-dom';
    import { Child } from './Child';
    
    class Parent extends React.Component {
      constructor(props) {
        super(props);
        this.changeName = this.changeName.bind(this);		// this의 bind 처리
        this.state = { name: 'Frarthur' };
      }
    
      changeName(newName) {
        this.setState({
          name: newName
        })
      }
    
      render() {
        return <Child name={this.state.name} onChange={this.changeName} />
      }
    }
    
    ReactDOM.render(
    	<Parent />,
    	document.getElementById('app')
    );
    1. 새로운 이름으로 state를 변경하는 changeName 이벤트 핸들러를 만들었다. this.setState()로 값을 바꿔준다.
    2. <Child /> 컴포넌트에는 onChange props를 추가하고 여기에 this.changeName을 할당한다.
    3. 또한, 이 때의 this가 Parent를 지칭하도록 생성자 함수 내에서 bind 처리를 한다.

     

    //📂Child.js
    
    import React from 'react';
    
    export class Child extends React.Component {
      constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this)
      }
    
      handleChange(e) {
        const name = e.target.value;
        this.props.onChange(name);
      }
    
      render() {
        return (
          <div>
            <h1>
              Hey my name is {this.props.name}!
            </h1>
            
            // onChange={this.props.onChange} 설정하면, onChange props는 실행하나 바뀐 이름을 반환하지 못함!!
            <select id="great-names" onChange={this.handleChange}>
              <option value="Frarthur">
                Frarthur
              </option>
    
              <option value="Gromulus">
                Gromulus
              </option>
    
              <option value="Thinkpiece">
                Thinkpiece
              </option>
            </select>
          </div>
        );
      }
    }
    1. <select> JSX에 onChange 이벤트 리스너를 추가한 뒤, this.props.onChange가 아닌 새로운 함수를 할당해야 한다.           * changeName은 변경된 값으로 state 최신화만 담당, handleChange(e) 이벤트 핸들러가 Child에서 value 변경값 전달을 담당
    2. handleChange(e) 이벤트 리스너를 만든다. 여기선, e.target.value를 받아, this.props.onChange() props로 반환한다.
    3. 그래서 select의 onChange 이벤트 리스너는 this.handleChange가 할당된다. 여기서도 this가 Child를 지칭하도록, 생성자 함수를 새로 만든 뒤 bind 처리한다.

    📒 Update Sibling Component(props) : child -> parent -> child

     

    앞선 코드에선, Child 컴포넌트가 1가지가 아닌 2가지 기능을 담당했다. (name changing + h1 displaying)

    컴포넌트는 기본적으로 단일기능을 담당하는게 이상적이므로, 이 두 가지 기능을 각각의 컴포넌트에 할당하고자 한다.

    //📂 Parent.js
    
    import React from 'react';
    import ReactDOM from 'react-dom';
    import { Child } from './Child';
    import { Sibling } from './Sibling';
    
    class Parent extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = { name: 'Frarthur' };
    
        this.changeName = this.changeName.bind(this);
      }
    
      changeName(newName) {
        this.setState({
          name: newName
        });
      }
    
      render() {
        return (
          <div>
            <Child onChange={this.changeName} />		// 값 변경 담당
            <Sibling name={this.state.name}/>					// 화면표시 담당
          </div>
        );
      }
    }
    
    ReactDOM.render(
      <Parent />,
      document.getElementById('app')
    );
    1. 렌더링을 <Child /> 와 <Sibling /> 따로 담당하며, Sibling 컴포넌트엔 name props를 추가한다.
    2. Child 컴포넌트는 name props(변경된 name state)를 받을 필요가 없으므로, 삭제한다.

     

    //📂 Sibling.js
    
    import React from 'react';
    
    export class Sibling extends React.Component {
      render() {
        let name = this.props.name;			// name props 전달
        return (
          <div>
            <h1>Hey, my name is {name}!</h1>
            <h2>Don't you think {name} is the prettiest name ever?</h2>
            <h2>Sure am glad that my parents picked {name}!</h2>
          </div>
        );
      }
    }
    1. name props를 전달받아, name이라는 변수에 저장한다.
    2. 변경되야하는 부분들을 {name} 변수로 대체한다.

    이처럼, 하나의 컴포넌트에서 복수요소를 렌더링하는 것보다, 입력과 출력을 담당하는 각각의 컴포넌트를 제작하는 방법이 일반적이다.


    새로운 개념이라기보다는, 기존에 배운 컴포넌트와 props, state를 통해 실무에 사용되는 제작방법을 튜토리얼한 내용이다.

    Parent에서는 state 저장과 전체 page 렌더링을 담당하고 있었다. 아마, index.js에 해당하는 부분일 것 같다.

    Child, Sibling에선 각각이 담당하는 변화값에 따른 state 변경, 변경된 state를 props로 받아 출력 기능이 작성되어 있다.

     

    특히, 클래스형 컴포넌트를 쓰면서 this의 오류를 줄이기 위해 bind 처리에 대해 유의하고 this 개념은 따로 공부해서 포스팅해야겠다.

    반응형

    'Front-End(Web) > React - 프레임워크(React, Next)' 카테고리의 다른 글

    [React.js] Components Seperation  (0) 2020.12.01
    [React.js] Inline Style  (0) 2020.11.30
    [React.js] Hooks - useEffect()  (0) 2020.11.28
    [React.js] Hooks - useState()  (0) 2020.11.27
    [React.js] Lifecycle  (0) 2020.11.27
Designed by Tistory.