티스토리 뷰

⚛️React란?

React는 facebook에서 만든 JS 라이브러리로, component를 사용해 웹페이지를 효과적으로 렌더링(rendering)합니다.

 

무슨 소리냐 하면, 예를 하나 들어보겠습니다. 어느 사이트에 회원가입을 한다고 해봅시다. 이름이랑 아이디, 비밀번호, 비밀번호 확인, 닉네임, 이메일, 전화번호 등을 입력하고 가입하기를 눌렀습니다. '비밀번호가 일치하지 않습니다'라는 알림 창이 뜨네요. 아니 근데 알림 창의 확인을 누르는 순간, 화면이 새로고침 되면서 제가 채운 정보가 다 사라지는 겁니다.

 

아니.. 비밀번호만 지우면 되잖아..?

 

이러면 사용자가 실수했을 때 모든 정보를 계속 다시 입력해야 합니다. 이런 불편함을 해결하기 위해 생각해낸 것이, 필요한 부분만 바꾸자입니다. 사용자와 정보가 오가면서 변화를 줘야 할 부분이 생기면 해당 component만 반응하도록 하는 것이죠.

그러면 웹도 페이지를 처음부터 끝까지 다시 불러오지 않아도 되니, 훨씬 빠르고 가볍게 작동합니다. 물론 React가 나오기 전부터 이런 문제를 해결하는 도구들이 등장했으나, 저희는 요즘 많이 쓴다는 React 관련 개념을 더 알아봅시다.

 

 

1️⃣ JSX 문법

JSX는 JavaScript 확장 문법으로, React에서 사용하는 문법입니다. 

const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;

// element를 화면에 렌더링 한다
ReactDOM.render(
  element,
  document.getElementById('root')
);

위 코드처럼 HTML과 비슷하게 생긴 코드를 JS에서 생성하고 렌더링 할 수 있습니다. 여기서 주의할 점은 진짜 HTML이 아니기 때문에 우리가 평소 HTML에서 사용하던 문법과 좀 다른 부분이 있다는 겁니다. 예를 들면 위의 처럼 JS 변수를 {}를 사용해서 element 사이에 집어넣을 수 있습니다.

 

function getGreeting(user) {
  if (user) {
    return <h1>Hello, {formatName(user)}!</h1>;
  }
  return <h1>Hello, Stranger.</h1>;
}

또한 자신이 정의한 함수를 건넬 수도 있고, if를 사용하여 조건에 따라 원하는 element를 전달할 수 있습니다.

 

2️⃣ Component

앞에서 말했듯이, React의 강점은 웹페이지를 여러 개의 component로 쪼개서 관리한다는 겁니다. 각 component는 독립적이고, 우리가 한번 만든 component를 여러 번 다시 사용할 수 있습니다.

 

component에는 class component와 function component가 있습니다.

 

Function Component

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

우리가 JS에서 함수를 생성하듯이 Welcome component를 만들어 봤습니다. 이때 prop(property)가 인자로 넘어오는데 이건 뒤에서 설명하겠습니다. 이번엔 class로 component를 만들어봅시다.

 

Class Component

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

class component는 React.Component를 상속받아야 합니다. class는 기본적으로 return()이 없고 render를 사용해야 합니다. 위 코드의 return은 render()의 return입니다.

 

서로 다른 방식으로 component를 만들어 봤지만 둘은 동일하게 작동합니다. 그럼 class component는 왜 있을까요? 바로! state를 사용하고 싶어서입니다.

 

 

3️⃣ Props & State

Props

props(property)부터 알아봅시다. 앞에서 component를 만들었는데, 저희는 여기에 어떤 정보를 전달하고 싶습니다. React에서는 props를 사용하여 다음과 같이 정보를 전달하면 됩니다.

function Welcome(props) {
  // 2. Hello 다음에 props.name 값을 표시한다.
  return <h1>Hello, {props.name}</h1>; 
}

// 1. Welcome에 name이라는 prop을 전달한다.
const element = <Welcome name="Sara" />; 
ReactDOM.render(
  element,
  document.getElementById('root')
);

<prop 이름>=<data>를 component attribute로 전달하고 함수에서는 {props.<prop 이름>}, class에서는 {this.props.<prop 이름>}으로 접근합니다. 즉, 저희가 준 정보가 props라는 object(객체)로 전해집니다.

 

 

State

props와 마찬가지로 state도 object입니다. 대신 state에는 우리가 이벤트 발생 등으로 바꾸고 싶은 데이터를 전달합니다. 다음 코드를 봅시다.

class Count extends React.Component {
  constructor(props) {
    super(props);
    this.state = {count: 0};
  }
    
  countUp = () => {
    this.setState({count: 1}); // count 값을 1로 바꾼다.
  };

  countDown = () => {
    this.setState({count: -1}); // count 값을 -1로 바꾼다.
  };

  render() {
    return (
      <div>
        <h1>Count: {this.state.count}</h1>
        <button onClick={this.countUp}>Up</button> 
        <button onClick={this.countDown}>Down</button> 
      </div>
    );
  }
}

class에 count라는 state를 생성합니다.  초기값은 0입니다. Up 버튼을 클릭하면 count가 1이 되고 Down을 클릭하면 count가 -1로 바뀝니다. React는 state 값이 변경되면 해당 component를 새로 렌더링 합니다. 이때 절대로 state 값을 직접 바꾸려고 하면 안 됩니다.

// Wrong
this.state.count = 1;

 

React가 state 값이 바뀐 걸 알아차리고 렌더링 하려면 setState라는 함수를 써줘야 합니다.

// Correct
this.setState({count: 1});

 

이번엔 버튼을 누를 때마다 값이 1씩 증가/감소하게 만들어봅시다. countUp과 countDown 함수를 다음처럼 고칩니다.

// 방법 #1
// 함수가 실행될 때마다 count가 1씩 증가한다.
countUp = () => {this.setState(count: this.state.count + 1)};

// 함수가 실행될 때마다 count가 1씩 감소한다.
countDown = () => {this.setState(count: this.state.count - 1)};

이전 state 값에 1을 더하거나 빼서 이제는 연속적으로 값이 변합니다. 하지만 이전 값을 사용해서 state를 업데이트할 때는 위의 방법보다는 setState에 함수를 건네주는 방법을 선호합니다. (setState()는 기본적으로 이전 state 값과 props를 인자로 가져옵니다)

 

// 방법 #2
// 함수가 실행될 때마다 count가 1씩 증가한다.
countUp = () => {
  this.setState((state, props) => (
  	{count: state.count + 1}
  ));
};

// 함수가 실행될 때마다 count가 1씩 감소한다.
countDown = () => {
  this.setState((state, props) => (
  	{count: state.count - 1}
  ));
};

이전 state 값을 하나만 사용할 때는 방법 1을 사용해도 코드가 잘 돌아갑니다. 문제는 한 번에 여러 setState를 호출할 때 발생합니다. React 문서에 따르면, state 업데이트는 동시에 일어나지 않는(Asynchronous: 비동기) 특성이 있습니다. 즉, 이벤트가 발생하여 setState가 실행되면 React는 값을 변경하라는 요청만 받고, 이벤트 핸들러가 끝나고 나서야 요청사항을 처리합니다.

countUp = () => {
  this.setState({count: this.state.count + 1}); // 1 증가 요청
  this.setState({count: this.state.count + 1}); // 1 증가 요청 (갱신)
  this.setState({count: this.state.count + 1}); // 1 증가 요청 (갱신)
  
 // 결국 마지막 요청에 따라 count는 1만 증가
};

 

만약 여러 번 setState를 호출하고 즉각 업데이트를 하고 싶다면 다음 코드처럼 함수를 전달합니다.

add = (state, props) => ({ count: state.count + 1 });

countUp = () => {
  this.setState(this.add); // count: 1
  this.setState(this.add); // count: 2
  this.setState(this.add); // count: 3
};

 

 

4️⃣ Hook

Hook는 React 16.8 버전에서 새로 추가된 기능으로, class 없이도 state를 사용할 수 있는 특성이 있습니다. Hook는 class가 아니라 function component에서 사용합니다. 간단히 몇 가지 Hook만 살펴봅시다.

 

 

State Hook

useState자신이 사용할 state와 state 값을 바꿀 때 사용하는 함수를 함께 반환합니다.

import React, { useState } from 'react';

function Example() {
  // "count"라는 변수와 setCount 함수를 생성한다.
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

위에서 생성한 count state의 값을 바꾸려면 setCount() 함수에 바꾸려고 하는 값을 전달하면 됩니다.

 

 

Effect Hook

useEffect는 function component에서 side effect를 수행하는 함수입니다. 여기서 side effect란, 화면이 일차적으로 렌더링 된 후 처리해야하는 부수적인 것들을 말합니다. 대표적으로 로딩 화면을 먼저 띄우고, fetch를 사용하여 데이터를 가져와야 하는 작업도 side effect입니다. effect인 이유는 이런 작업이 다른 component에 영향을 주기 때문에 붙여진 이름입니다.

 

class를 사용할 때는 side effect를 componentDidMount, componentDidUpdate, componentWillUnmount 등의 life cycle method로 처리했습니다. component를 생성(Mount)하고 업데이트(Update)하고 제거(Remove)할 때 실행할 작업을 life cycle method로 나눠서 작업하는 겁니다.

// component가 처음 렌더링 된 후 다음 작업을 실행한다.
async componentDidMount () {
  const movies = await fetch('http://example.com/movies.json');
  this.setState({ movies, isLoading: false });
}

render() {}

 

하지만 이젠 function component 안에서 useEffect로도 이 작업을 할 수 있습니다. class가 아니어서 this.setState 대신 state hook를 사용해야 합니다.

 useEffect(async () => {
   const movies = await fetch('http://example.com/movies.json');
   setMovie(movies);
   setLoading(false);
 });
 
 return();

 

이 외에도 다양한 hook이 있으니 다음에 더 알아보도록 합시다. 오늘은 여기까지🤗


[참고자료]

 

State and Lifecycle – React

A JavaScript library for building user interfaces

reactjs.org

 

비동기로 동작하는 react의 setState에 대하여

Constructor 메서드 내에서 state를 초기화 하는 작업이 없다면, 해당 React 컴포넌트에서 생성자를 구현하지 않아도 된다. 초기화를 위해서는 아래와 같이 작성한다또는 멤버변수(클래스 필드)를 사

velog.io

 

State updates might be asynchronous

What exactly do they mean? If I understand it correctly, I can't use this.state when calculating new state, unless I pass a function as a first parameter to setState(): // Wrong this.setState({a: ...

stackoverflow.com

 

React Hooks: useEffect 사용법

Engineering Blog by Dale Seo

www.daleseo.com

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함