조건부 렌더링

Yeom Jae Seon·2021년 2월 6일
0

React공식문서 공부

목록 보기
6/11
post-thumbnail

지금까지 총정리


React에서 사용하는 JSX를 배웠고 이는 객체를 생성한다고 배웠다. 그 객체는 바로 리액트의 가장 작은 단위인 React 엘리먼트이고 이는 말한것처럼 일반 객체이다.
이객체는 화면을 어떻게 구성해야할지 실제 DOM을 어떻게 구성해야할지 정의된 객체 즉, 설명서 이다. 엘리먼트를 렌더링 시키는 방법으론 루트 DOM 노드와 연결해야하는데 좀더 자세한 방법으론 ReactDOM.render()함수를 이용한다. 참고로 React DOM이 리액트 엘리먼트를 보고 DOM을 업데이트하는 방식은 효율적으로 업데이트가된다. (이전 엘리먼트와 비교해서 실제로 변경된부분 계산 -> 그 부분을 실제 DOM에 업데이트)
DOM태그만으로 React 엘리먼트를 표현하는건아니고 컴포넌트를 통해서 엘리먼트를 표현할수도 있다. 컴포넌트란 props를 입력받아 React 엘리먼트를 반환하는 아이이다.
이는 함수나 클래스로 작성되어질수있다. 그리고 입력되어지는 props는 읽기전용이다. (해당 props 받은 컴포넌트에서 직접수정하면안된다..)
그리고 유상태 컴포넌트를 통해서 컴포넌트 내부에서 rendering이 자체적으로 되도록 할수있다.(ReactDOM.render()를 명시적으로 여러번 호출하지 않아도!)
그리고 리액트 엘리먼트에 이벤트를 주는방법으론 HTML에 inline방식과 매우 유사하며 camelCase, 합성이벤트, JSX의 속성주는 방법을통한 {}에 함수를 제공하는 등의 차이점이 존재한다.

간단하게 정리하려했는데 좀길어졌다.
이제는 React어플의 상태에 따라서 컴포넌트중 몇개만을 렌더링 할수 있는 조건부 렌더링을 배워보겠다.

조건부 렌더링


React에서 조건부렌더링은 JS에서의 조건처리와 같다.(if, 삼항연산자, && ...)
이러한 조건처리를 이용하면 React는 현재 상태에 맞게 UI를 업데이트 할수있다.(원하는 조건의 상태에 따라서..)

오늘의 점심을 고르는 컴포넌트를 이용해 뭘먹을지 골라보겠다.
선택지는 햄버거와 피자밖에없다.

import ReactDOM from "react-dom";

const SelectHambergur = (props) => <h1>햄버거 고름!</h1>;
const SelectPizza = (props) => <h1>피자 고름!</h1>;

const TodayLunch = (props) => {
  if (props.food === "햄버거") {
    return <SelectHambergur />;
  }
  return <SelectPizza />;
};

const rootElement = document.getElementById("root");
ReactDOM.render(<TodayLunch food="햄버거" />, rootElement);

(예시만들다가 컴포넌트 이름을 소문자로 했다가 다시 수정했다. 리액트는 컴포넌트이름 소문자로하면 DOM 태그로된 엘리먼트와 착각한다 했다.!)

TodayLunch컴포넌트를 리액트가 보면 props로 속성값과 children을 전달한다했지?
위 예시에선 속성 food에 "햄버거"를 TodayLunch컴포넌트에 전달한다. 그럼 TodayLunnch컴포넌트에서 props.food에 맞게 필요한 컴포넌트를 리턴한다.

이렇게 if문을 사용해서 적절하게 필요한 컴포넌트를 리턴할수 있다.
컴포넌트는? 엘리먼트를 리턴한다했고 엘리먼트는 Object라고 배웠으니 if에 따라서 객체를 리턴하는게 이상한가? - JS에서도 당연한일.

  • 컴포넌트는 엘리먼트를 리턴한다. 엘리먼트는 객체이므로 조건에 따라서 다른 엘리먼트를 제공해서 다르게 렌더할수 있다. - 이 건 자명한 사실임!

엘리먼트 변수


(참고로 React 공식문서 시리즈에서 얘기하는 엘리먼트는 React 엘리먼트를 얘기하는 것입니다. 일반 DOM 엘리먼트와 착각하지말것.)
주제 그대로 엘리먼트를 저장할 변수를 만들어서 해당 변수를 렌더링 하는것이다.
그냥 렌더링하는게 아니라 조건에 따라서 해당 변수에 다른 엘리먼트(객체)를 할당한다.

LunchControl이라는 유상태 컴포넌트를 만들어서 state에 따라 햄버거 컴포넌트를 변수에 할당할지 피자 컴포넌트를 변수에 할당할지 조건을 만들어 해당 변수를 랜더 시켜보자.

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

const HamburgerButton = (props) => (
  <button onClick={props.onClick}>햄버거</button>
);
const PizzaButton = (props) => <button onClick={props.onClick}>피자</button>;

class LunchControl extends React.Component {
  constructor(props) {
    super(props);
    this.state = { food: "hamburger" };
  }
  clickHamburger = () => {
    this.setState({ food: "hamburger" });
  };
  clickPizza = () => {
    this.setState({ food: "pizza" });
  };
  render() {
    let button;
    if (this.state.food === "pizza")
      button = <HamburgerButton onClick={this.clickHamburger} />;
    else button = <PizzaButton onClick={this.clickPizza} />;
    return (
      <>
        <h1>오늘의 점심은~</h1>
        <h2>{this.state.food}</h2>
        {button}고르기
      </>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<LunchControl />, rootElement);

컴포넌트의 상태(state)에 따라서 button변수에 다른 컴포넌트를 할당 받아서 해당 button변수를 렌더하는 예시이다.
중요한건 방법이아니라 컴포넌트는 엘리먼트를 리턴하기 때문에 엘리먼트는 객체이므로 변수에 할당하는 것도 조건에 따라서 다르게 변수에 할당하는것도 모두 가능하다는 것이다.

이렇게 if문을 통해서 조건에 따라서 원하는 컴포넌트를 렌더시킬수 있다.

그치만 if문을 사용하는 것보단 간단하게 JSX내에서 inline으로 조건문을 사용할수도 있다.

  • 유상태 컴포넌트에서 변수에 엘리먼트(컴포넌트가 리턴하는 객체)를 상태에 따라 다르게 할당하고 해당 변수를 렌더시킴

&&이용해서 조건부 렌더링하기

&&는 JS문법이다.
이문법을 이용해서 if를 사용하지않고 JSX내 inline방식으로 조건부 렌더링을 할수도 있다.
const result = expr && true는 참고로 expr이 true이면 result에 true를 할당한다는 문법이다.
&&는 AND 와같은 논리연산자인데 true && expr는 expr이 true이면 true이고 false이면 false이다. 왜냐면 &&가 true이려면 둘다 true여야 하기 때문이다.
false && expr은 무조건 false이다. expr이 true던 false든 앞에 false가 있으므로 false이다. 이를 응용한 방법? 사용한 방법이라고 생각하면된다.

  render() {
    return (
      <>
        <h1>오늘의 점심은~</h1>
        <h2>{this.state.food}</h2>
        {this.state.food === "pizza" && (
          <HamburgerButton onClick={this.clickHamburger} />
        )}
        {this.state.food === "hamburger" && (
          <PizzaButton onClick={this.clickPizza} />
        )}
        고르기
      </>
    );
  }

위의 예시의 if문을 통해서 return()밖에서 변수에 다른 컴포넌트 할당하고 해당 변수를 랜더하는 과정 생략하고 바로 return()내부에서 조건에따른 원하는 컴포넌트렌더링을 끝냈다. 즉, JSX내부에서 조건부 렌더링을 한거지?

좀 간단한가? 예시자체가 좀 복잡해서 차이점을 모를수도있지만 이런방법도 있다 알아놓으면된다.

  • 큰 차이점이라기 보단 다른 JS 문법을 이용한것 뿐이다. if문으로 조건에 따라 다른 컴포넌트 렌더링할수도있지만 JS 논리연산자 &&를 이용할수도 있다. 이걸이용하면 JSX내부에서 inline으로 조건부 렌더링을 할수 있다.

if-Else(삼항연산자)로 JSX inline에서 조건부렌더링 하기


이것도 뭐 JS문법만 다른 표현방식이지 조건에 따라 다른 컴포넌트(리액트 엘리먼트)를 렌더하는 컨셉은 같다.
삼항연산자를 이용하면 &&와 마찬가지로 JSX 내부에서 조건부 렌더링을 할수 있다.(if를 이용해서 JSX외부에서 변수에 엘리먼트할당받아 해당 변수를 렌더링하는 방법과는 다르고 &&와 같이 JSX내부에서 바로 조건에 따른 렌더링을 행한다. 그치만 &&와는 다르게 false일때도 무언가를 행할수 있다는게 차이점이다.)

  render() {
    return (
      <>
        <h1>오늘의 점심은~</h1>
        <h2>{this.state.food}</h2>
        {this.state.food === "pizza" ? (
          <HamburgerButton onClick={this.clickHamburger} />
        ) : (
          <PizzaButton onClick={this.clickPizza} />
        )}
        고르기
      </>
    );
  }

랜더하는 부분이 이런식으로 바뀌었소이다.

지금까지 한 조건부렌더링 정리하자면

  • 리액트 엘리먼트는 일반 객체이고 이객체를 JS 조건문을 이용해서 조건에 따라 다르게 렌더링 시킬수 있다.
  • if, &&, 삼항연산자를 사용할수있고 if는 조건에 따라서 JSX외부에서 조건에 따라 다른 리액트 엘리먼트를 변수에 할당해서 사용하고 &&와 삼항연산자는 JSX내부에서 바로 조건에 따라 다른 엘리먼트를 랜더링 시킬수 있다.

null이용해서 컴포넌트 랜더링 자체를 막기


컴포넌트는 리액트 엘리먼트를 리턴해야한다고 배웠다
그치만 null을 리턴해서 렌더링 자체를 막을수 있다.
이를 통해 유상태 컴포넌트 내에서 상태에 따라 어떤 컴포넌트는 랜더링을 막을수 있다.

피자나라에선 햄버거를 먹으면 안되는 금지 조약을 걸어서 햄버거 고르라는 컴포넌트가 랜더링되면 Warning컴포넌트가 랜더링되고 피자 고르라는 컴포넌트가 랜더링되면 null을 리턴해서 Warning컴포넌트의 렌더링을 막아보자.

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

const HamburgerButton = (props) => (
  <button onClick={props.onClick}>햄버거</button>
);
const PizzaButton = (props) => <button onClick={props.onClick}>피자</button>;

const Warning = (props) => {
  if (props.food === "hamburger") return null;
  return <p>❗❗❗❗ 참고로 햄버거 먹으면 사형이다. 그래도 먹을거냐?</p>;
};

class LunchControl extends React.Component {
  constructor(props) {
    super(props);
    this.state = { food: "hamburger" };
  }
  clickHamburger = () => {
    this.setState({ food: "hamburger" });
  };
  clickPizza = () => {
    this.setState({ food: "pizza" });
  };
  render() {
    return (
      <>
        <h1>오늘의 점심은~</h1>
        <h2>{this.state.food}</h2>
        {this.state.food === "pizza" ? (
          <HamburgerButton onClick={this.clickHamburger} />
        ) : (
          <PizzaButton onClick={this.clickPizza} />
        )}
        고르기
        <Warning food={this.state.food} />
      </>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<LunchControl />, rootElement);

이렇게 this.state.foodhamburger이면 null을 리턴해서 Warning컴포넌트 렌더링 자체를 막는 방법도있다.

클래스 컴포넌트에서 null을 반환하는것과 생명주기 함수는 상관이없다.
null을 반환하여 랜더링이 없어도 생명주기함수는 실행중이다.(state가 업데이트되는 중이므로..)

  • 컴포넌트는 리액트 엘리먼트를 리턴해야한다고 배웠는데 null을 리턴해서 렌더링을 자체를 막을수도 있다.
  • 컴포넌트가 null리턴안해도 &&나 삼항연산자 if를 사용해서 렌더링을 막을수도 있는 방법이 있다.

위 내용은 공식문서를 보고 공부한 내용입니다.
https://ko.reactjs.org/docs/conditional-rendering.html

0개의 댓글