React 핵심 개념

마데슾 : My Dev Space·2020년 2월 16일
0

React

목록 보기
1/7

Data Flow

  • 단방향 데이터 흐름
  • 데이터흐름 : 부모컴포넌트 => 자식컴포넌트
  • 자식컴포넌트에서 직접적으로 부모컴포넌트에 전달하는 것은 불가능하다
    - 간접적으로는 가능

props

상위 컴포넌트가 하위 컴포넌트에게 내려주는 데이터
하위컴포넌트는 props를,

  • 단순히 사용만 할 수 있다
  • 변경할 수 없다
const App = () => (
  <div>
    <h2>To Do List !</h2>
    <TodoList todos={["eat pizza", "eat rice"]} />
  </div>
);

const TodoList = props => (
  <ul>
    <li>{props.todos[0]}</li>
    <li>{props.todos[1]}</li>
  </ul>
);

State

컴포넌트가 갖는 상태,
객체의 형태로 컴포넌트 내에서 보관하고 관리한다.

  • class 컴포넌트로 작성되어야 한다
  • 값을 변경할 땐 반드시 setState 메서드를 사용해야 한다
  • state 값이 변경되면 render() 함수가 실행된다.
class GroceryList extends React.Component {
  constructor(props) {
    super(props);

    this.state = { // state 정의
      isBold: false 
    };
  }

  onListItemClick = () => {
    this.setState({ // state 변경
      isBold: !this.state.isBold
    });
  };

  render() {
    const style = {
      fontWeight: this.state.isBold ? "normal" : "bold"
    };

    return (
      <ul>
        <li style={style} onClick={this.onListItemClick}>
          {this.props.todo[0]}
        </li>
        <li>{this.props.todo[1]}</li>
      </ul>
    );
  }
}
  • 함수형 setState
    - 첫번째 인자 : 이전 state
    • 두번째 인자 : 업데이트가 적용된 시점의 props
this.setState((state, props) => ({
  counter: state.counter + props.increment
}));

Life Cycle

컴포넌트가 브라우저에 보여질 때, 업데이트될 때, 사라질 때 각 단계 전, 후로 특정 메서드가 호출된다

  • 컴포넌트에 어떠한 이벤트가 발생하면 Life Cycle 메서드가 실행되는데, 우리는 이 메서드를 적절히 이용하여 원하는 타이밍에 원하는 작업을 수행할 수 있다.
  • Life Cycle 메서드를 사용하려면 반드시 class 컴포넌트로 작성해야한다.
    - 함수형 컴포넌트에서는 Life Cycle 메서드가 실행되지 않기때문

Life Cycle 예시

react 공식 문서에 예시가 잘나와 있어서 가져왔다

class Clock extends React.Component {
  constructor(props) { // 1. Clock 컴포넌트의 생성자 호출
    super(props);
    this.state = {date: new Date()}; // 2. 현재 시각이 포험된 객체로 초기화
  }

  componentDidMount() { // 5. componentDidMount() 메서드 호출
    this.timerID = setInterval( // 6. 1초에 한번씩 tick 메서드 호출
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
  /* Clock 컴포넌트가 DOM으로부터 한번이라도 삭제된 적이 있다면
  React는 타이머를 멈추기 위해 componentWillUnmount 메서드를 호출한다. */
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({ // 7. state가 변경되면 render 메서드를 다시 호출한다.
      date: new Date()
    });
  }

  render() { // 3. render 메서드 호출
    return ( // // 4. 화면 렌더링
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

생성

  1. 작성된 컴포넌트 호출
  2. constructor() => 생성자 호출
  3. 렌더 메소드가 실행된다 => JSX를 반환하여 화면에 그려지는 작업이 실행된다
  4. componentDidMount 메서드 실행

업데이트

  1. state값 변경
  2. render 함수 실행
  3. 업데이트된 값이 화면에 보여진다 => 화면렌더링
  4. componentDidUpdate 메서드 실행

functional component vs class component

함수형 컴포넌트

import React from 'react';
import ReactDOM from 'react-dom';

const HelloWorld = () => (
  <div>HELLO WORLD</div>
);

ReactDOM.render(<HelloWorld />, document.getElementById("root"));
  • 순수 자바스크립트 함수를 이용하여 컴포넌트를 정의한 것
  • 선언하기가 편리하다
  • 단순히 데이터를 받아들여 어떤 형태로 표시하기 때문에 'stateless' 컴포넌트라고도 한다
  • 주로 UI 렌더링을 담당한다 (예시 : Button 구성 요소)
  • state를 사용할 필요가 없는 경우 함수형 컴포넌트를 사용한다
    • 클래스형 컴포넌트보다 메모리 자원을 덜 사용한다
  • state와 life cycle 기능을 사용할 수 없다
    - v16.8 업데이트 이후 리액트 훅(Hooks)이라는 기능이 도입되어 사용이 가능하다고 한다..!!

렌더링된 값들을 고정시킨다.

해당 특징은 신기해서 따로 빼서 글을 정리한다. => 예제

예제에서,
1. Follow버튼을 누르고
2. 3초가 지나기 전에 체크박스 옵션을 바꾼다
3. 알림창의 글을 읽어본다

결과,

  • 함수형 컴포넌트 : Follow 버튼을 누르고 체크박스 옵션을 바꾸면 알림창에 Follow 버튼을 누르기전 옵션값이 알림창에 잘 들어가있다.
  • 클래스형 컴포넌트 : Fllow 버튼을 누른 후 바꾼 옵션값이 알림창에 들어가있다

이 예제에서는 함수형 컴포넌트가 보여주는 패턴이 올바른 케이스이다. 내가 어떤 사람을 팔로우하고 다른 사람의 프로필로 이동했다 하더라도 컴포넌트가 이를 헨갈려서는 안된다.

클래스형 컴포넌트에서 버튼을 누른 후 옵션값을 바꿀경우에 알림창에 바뀐 옵션값을 노출하는 이유는?

class ProfilePage extends React.Component {
  showMessage = () => {
    alert('Followed ' + this.props.user);
  };

showMessage 메서드는 this.props.user로부터 값을 불러온다. props는 리액트에서 불변값이지만 this는 변경이 가능하고 조작할 수 있다.

리액트가 시간이 지남에 따라 this를 변경하기 때문에 render나 라이프사이클 메서드를 호출할 때 업데이트된 값들을 읽어올 수 있는 것이다.

따라서 요청이 진행되고 있는 상황에서 클래스 컴포넌트가 다시 렌더링 된다면 this.props 또한 바뀐다. 그래서 showMessage 메서드가 새로운 propsuser를 읽는 것이다

해결방법
자바스크립트의 클로저로 해결할 수 있다.
props의 값을 render될때의 값으로 고정

class ProfilePage extends React.Component {
  render() {
    // props의 값을 고정!
    const props = this.props;

    // Note: 여긴 *render 안에* 존재하는 곳이다!
    // 클래스의 메서드가 아닌 render의 메서드
    const showMessage = () => {
      alert('Followed ' + props.user);
    };

    const handleClick = () => {
      setTimeout(showMessage, 3000);
    };

    return <button onClick={handleClick}>Follow</button>;
  }
}

렌더링된 값을 고정시키고 싶을때는 함수형 컴포넌트를 사용하자.

클래스형 컴포넌트

import React from "react";
import ReactDOM from "react-dom";

class TodoListItem extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      done: false
    };
  }

  onListItemClick() {
    this.setState({
      done: !this.state.done
    });
  }

  render() {
    const style = {
      textDecoration: this.state.done ? "line-through" : "none"
    };

    return (
      <li style={style} onClick={this.onListItemClick.bind(this)}>
        {this.props.todo}
      </li>
    );
  }
}

ReactDOM.render(
  <TodoListItem todo={["one", "two"]} />,
  document.getElementById("root")
);
  • ES6 클래스 사용
  • props에 this.props로 접근
  • state 기능 사용가능
  • lifecycle 메서드 사용가능

참고블로그

profile
👩🏻‍💻 🚀

0개의 댓글