[React] 리액트 개념 정리

seomoon·2021년 9월 1일
0
post-custom-banner

21 09 01 - 21 09 03

Velopert 벨로퍼트와 함께하는 모던 리액트 (https://react.vlpt.us/)를 보고 개인적인 복습을 위해 정리한 내용입니다. 원문을 보시는 것을 추천합니다. (1장 리액트 입문 부분)

React

  • Virtual DOM : 브라우저에 실제로 보여지는 DOM이 아니라 메모리 상에만 존재하는 가상의 DOM으로,
    그냥 자바스크립트 객체이기 때문에 작동 속도가 실제 DOM 보다 훨씬 빠르다.

  • 리액트는 상태(state)가 업데이트 되면 Virtual DOM에 먼저 렌더링한 후,
    실제 DOM과 비교해 차이가 있는 부분만 부분적으로 패치한다.


Environment

  • Webpack, Babel:
    - Webpack : 컴포넌트별로 분리해 작성한 여러 개의 파일을 하나로 합쳐주는 역할
    - Babel : JSX 등 최신 자바스크립트 문법을 사용하기 위해 (최신 자바스크립트 문법을 기존 문법으로 변환해주는 트랜스파일러. 브라우저에서 아직 지원하지 않거나 일부 브라우저만 지원하는 문법을 사용할 수 있게 해준다. )

Component

  • 컴포넌트 : 재사용 가능한 UI 조각.

  • 리액트 컴포넌트를 작성할 땐 리액트를 import해야 한다.
    import React from 'react';

  • ReactDOM.render() : 브라우저에 있는 실제 DOM 내부에 리액트 컴포넌트를 렌더링해주는 메소드.


JSX

  • 리액트 Fragment : <></>, 브라우저 상에 실제 엘리먼트로 나타나지 않음. 리액트 컴포넌트는 반드시 하나의 태그로 감싸져 있어야 하는데, 단순히 감싸기 위한 목적으로 불필요한 div를 사용하는 대신 Fragment를 사용할 수 있다.

  • 인라인 스타일은 객체 형태로 작성해야 하며, 스타일 속성 이름은 카멜케이스(background-color -> backgroundColor)로 작성해야 한다.

const style = {
    backgroundColor: 'black',
    fontSize: 24
  }

 <div style={style}>{name}</div>
  • css class는 class 대신 className 으로 작성.

  • JSX 내부 주석은 {/* 이 안에 */} 작성. (중괄호로 감싸야 함)

  • 태그 안에서는 // 주석 사용 가능. (<Hello //주석 />)


props

  • defaultProps : 컴포넌트에 props를 지정하지 않았을 때 기본적으로 사용할 값 설정.
import React from 'react';

function Hello({ color, name }) {
  return <div style={{ color }}>안녕하세요 {name}</div>
}

Hello.defaultProps = {
  name: '이름없음'
}
  • props.children : 하위 컴포넌트를 조회하고 싶을 땐 props.children 을 사용한다.
return <div>{props.children}</div>;

조건부 렌더링

  • 주로 삼항 연산자 또는 && 연산자를 사용해 처리한다.

  • JSX에서 null, false, undefined 를 렌더링하면 아무것도 나타나지 않는다.

  • props 값 할당을 생략하면 true 가 할당된다. (isSpecial === isSpeicial={true})


useState

  • 사용자 인터랙션에 따라 바뀌는 동적인 부분을 구현할 때 state를 사용한다.

  • 원래 클래스형 컴포넌트에서만 상태를 사용할 수 있었지만, 리액트 16.8에서 Hooks이 도입되면서, 함수형 컴포넌트에서도 상태를 관리할 수 있게 되었다.

  • useState Hook을 이용해 함수형 컴포넌트에서 state를 관리할 수 있다.

  • Setter 함수의 사용 :
    - 새로운 state 값을 파라미터로 넣어주는 방식
    setValue(value + 1);

    • 콜백 함수를 등록하는 방식 (함수형 업데이트)
      setValue(prevValue => prevValue + 1);
    • 함수형 업데이트 방식은 컴포넌트 최적화와도 관련되어 있다. (나중에)
  • 이벤트 처리 : onClick={onIncrease()} X, onClick={onIncrease} OK
    (전자는 렌더링되는 시점에서 함수가 호출되어 버림. )

  • 여러 개의 input 태그 상태 관리 :

import React, { useState } from 'react';

function InputSample() {
  const [inputs, setInputs] = useState({
    name: '',
    nickname: ''
  });

  const { name, nickname } = inputs; // 비구조화 할당을 통해 값 추출

  const onChange = (e) => {
    const { value, name } = e.target; // 우선 e.target 에서 name 과 value 를 추출
    setInputs({
      ...inputs, // 기존의 input 객체를 복사한 뒤
      [name]: value // name 키를 가진 값을 value 로 설정
    });
  };

  const onReset = () => {
    setInputs({
      name: '',
      nickname: '',
    })
  };


  return (
    <div>
      <input name="name" placeholder="이름" onChange={onChange} value={name} />
      <input name="nickname" placeholder="닉네임" onChange={onChange} value={nickname}/>
      <button onClick={onReset}>초기화</button>
      <div>
        <b>: </b>
        {name} ({nickname})
      </div>
    </div>
  );
}

export default InputSample;
  • useState에서 문자열이 아니라 객체로 상태를 관리한다.
  • input 태그에 name을 설정하고, 이벤트가 발생했을 때 이 값을 참조한다. (e.target.name: e.target.value)
  • 객체 state를 수정할 때는 직접 수정하면 안 되고, 새로운 객체를 만들어 사용해야 한다.
    spread 연산자 (...) 를 사용해 기존 객체를 복사해 사용한다.
//XXX
inputs[name] = value;

//OOO
setInputs({
  ...inputs,
  [name]: value
});
  • 이렇게 불변성을 지켜주어야만
    • 리액트 컴포넌트에서 상태 업데이트를 감지할 수 있고, 이에 따라 리렌더링이 진행될 수 있다.
      (setState()를 거치지 않고 기존 상태를 직접 수정하게 되면 값이 바뀌어도 리렌더링이 일어나지 않는다. )
    • 컴포넌트 업데이트 성능을 최적화할 수 있다.

useRef

  • 컴포넌트에서 특정 DOM 요소를 선택해야 할 때
  const nameInput = useRef(); //Ref 객체 생성
  
  const onReset = () => {
    setInputs({
      name: '',
      nickname: ''
    });
    nameInput.current.focus(); //Ref 객체의 current 값으로 접근
  };

  <input
	name="name"
	onChange={onChange}
	value={name}
	ref={nameInput} //ref 지정
  />
  • 컴포넌트 안에서 접근할 수 있는 변수 관리 :

    • useRef 로 관리하는 변수는, 값이 바뀌어도 컴포넌트가 리렌더링 되지 않는다.
      (함수형 컴포넌트 내부에서 useRef를 사용하지 않고 일반 변수를 선언하면, 컴포넌트가 렌더링될 때마다 값이 초기된다. state를 사용하면, state 값이 설정될 때마다 컴포넌트가 리렌더링된다. )

    • 리액트의 state는 setter를 호출하고 나서 렌더링이 된 이후에 업데이트된 상태를 조회할 수 있는 반면,
      useRef로 관리하는 변수는 설정 후 바로 조회할 수 있다.

    • useRef() 를 사용할 때 파라미터를 넣으면, 이 값이 Ref 객체 .current 의 기본값이 된다.
      .current를 통해 값을 수정하거나 조회할 수 있다.

  const nextId = useRef(4);
  const onCreate = () => {
    nextId.current += 1;
  };

배열

  • 배열을 사용해 컴포넌트를 렌더링하려면, map() 함수를 사용한다.

  • 리액트에서 배열을 렌더링할 때는 key props를 반드시 설정해야 한다.
    key는 고유한 값으로 설정해야하며 (주로 id 값으로 설정, 중복되는 key가 있으면 업데이트가 제대로 이루어지지 않는다. ), 만약 key 로 설정할만한 값이 없다면 map() 함수의 두 번째 파라미터인 indexkey로 사용할 수 있다.

  • key props가 필요한 이유 :
    key가 없다면 배열에 변경 사항이 생겨서 리렌더링을 할 때 비효율적인 방식으로 렌더링을 하게 된다. (ex : a, b, d, e 사이에 c를 추가하는 경우 b와 d 사이에 c를 추가하는 게 아니라
    a, b, d->c, e->d, e 와 같은 방식으로 삽입된다. )
    key가 있으면 수정되지 않는 기존의 값은 그대로 두고 원하는 내용만 삽입하거나 삭제할 수 있다.

배열에 항목 추가/제거/수정하기

  • 배열에 변화를 줄 때에도 객체와 마찬가지로 불변성을 지켜야 한다.
    push, splice, sort 등 기존 배열을 수정하는 메소드는 사용하면 안 된다.

    • 배열에 항목 추가하기

      • spread ... 연산자 사용 (기존 배열을 펼쳐서 복사해 새로운 배열에 담을 수 있다)
        setUsers([...users, user]);

      • concat 함수 (기존의 배열을 수정하지 않고 새로운 배열 반환)
        setUsers(users.concat(user));

    • 배열의 항목 제거하기

      • filter 함수 (배열에서 특정 조건이 만족하는 원소들만 추출해 새로운 배열을 생성함)
      setUsers(users.filter(user => user.id !== id)); 
      //id === user.id인 항목을 제거
    • 배열의 항목 수정하기
      - 배열을 업데이트할 때도 map() 함수를 사용할 수 있다.

      const onToggle = id => {
        setUsers(
          users.map(user =>
            user.id === id ? { ...user, active: !user.active } : user
          )
        );
      };

      해당하는 id 의 유저 active 값을 반전시켜준다.


useEffect

  • useEffect 를 사용해 컴포넌트 마운트/언마운트/업데이트(특정 props가 바뀔 때) 시 수행할 작업을 설정할 수 있다.

deps 배열이 빈 배열인 경우

  • useEffect 첫 번째 파라미터는 콜백 함수, 두 번째 파라미터는 의존값 배열(deps)를 넣는다.
    deps 배열에 있는 항목의 값이 바뀔 때마다 콜백 함수가 호출된다.
    deps로 빈 배열을 넣으면, 컴포넌트가 마운트될 때만(처음 렌더링될 때) useEffect에 등록한 함수가 호출된다.

  • useEffect는 함수를 반환할 수 있다. 이 때 반환되는 함수는 cleanup 함수라고 부른다.
    deps가 비어있는 경우 컴포넌트가 언마운트될 때 cleanup 함수가 호출된다.

  • 마운트/언마운트 :

    • 마운트 시 주로 하는 작업
      • props 로 받은 값을 컴포넌트의 로컬 상태로 설정
      • 외부 API 요청
      • 라이브러리 사용
      • setInterval을 통한 반복작업, 또는 setTimeout을 통한 작업 예약
    • 언마운트 시 주로 하는 작업
      • setInterval, setTimeout을 사용해 등록한 작업 clear하기 (clearInterval, clearTimeout)
      • 라이브러리 인스턴스 제거 (?)

deps 배열에 값이 있는 경우

  • deps 배열에 값을 넣으면, 해당 값이 바뀔 때에도 useEffect의 콜백 함수가 호출되며,
    값이 바뀌기 직전에 cleanup 함수가 호출된다.

  • useEffect 안에서 사용하는 상태나 props는 반드시 deps에 넣어주어야 한다. 그렇지 않으면 useEffect에 등록한 함수가 실행될 때 가장 최신 값을 참조할 것이라고 보장할 수 없다.

deps 배열을 생략한 경우 (=useEffect 의 두 번째 파라미터 생략)

  • 컴포넌트가 리렌더링될 때마다 콜백 함수가 호출된다.

    *리액트 컴포넌트는 기본적으로 부모 컴포넌트가 리렌더링되면 자식 컴포넌트는 바뀐 내용이 없더라도 리렌더링된다.
    (실제 DOM에서는 바뀐 내용이 있는 컴포넌트만 업데이트되지만, Virtual DOM에서는 전부 렌더링된다. )

  • useEffect 완벽 가이드(https://rinae.dev/posts/a-complete-guide-to-useeffect-ko) 읽어보기


useMemo

  • 이미 연산된 값을 재사용함으로써 성능 최적화를 할 수 있다.
    ("memoized" : 이전에 연산해둔 값을 재사용하는 것을 의미함. )
const count = countActiveUsers(users);

const count = useMemo(() => countActiveUsers(users), [users]);
  • 첫 번째 파라미터 : 콜백 함수 (연산 함수),
    두 번째 파라미터 : deps 배열

  • deps 배열 안의 내용이 바뀌면, 콜백 함수를 호출해 값을 연산해주고, 내용이 바뀌지 않았다면 이전에 연산한 값을 재사용하게 된다.


useCallback

  • useMemo는 특정 (연산의) 결과 값을 재사용할 때, useCallback은 특정 함수를 재사용할 때 쓴다.
    useCallbackuseMemo를 기반으로 만들어졌다. (useMemo로 대체할 수도 있다. )

  • 컴포넌트 내부에 작성한 함수들은 컴포넌트가 리렌더링될 때마다 새로 선언된다.
    함수를 선언하는 데에 많은 비용이 드는 건 아니지만,
    나중에 컴포넌트 최적화 작업을 할 때는 함수의 재사용이 필수이기 때문에 useCallback을 사용해야 한다.

  • 함수 안에서 사용되는 props나 상태는 반드시 deps 배열에 포함시켜야 한다.

  • 함수 안에서 state를 업데이트할 때, 함수형 업데이트를 하면, setState에 등록하는 콜백함수의 파라미터에서 최신 state를 참조할 수 있어 deps에 state를 넣어주지 않아도 된다.


React.Memo (컴포넌트 렌더링 최적화 작업)

  • React DevTools > 설정 > Highlight Updates : 리렌더링되는 컴포넌트를 확인할 수 있다.

  • React.Memo : 컴포넌트의 props가 바뀌지 않았다면, 컴포넌트 리렌더링을 방지해 컴포넌트 성능 최적화를 해주는 함수.
    (리렌더링이 필요한 상황에서만 리렌더링하도록 설정할 수 있다. )

  • 사용 방법은,
    컴포넌트를 export할 때 export default React.memo(component_name)와 같이 감싸주기만 하면 된다.

  • React.memo의 두번째 파라미터로 콜백 함수(propsAreEqual 함수)를 사용해 특정 props만 비교하는 것도 가능하지만, 잘못 사용하면 오히려 의도치 않은 버그가 발생하기 쉽기 때문에 주의해야 한다.

export default React.memo(
  UserList,
  (prevProps, nextProps) => prevProps.users === nextProps.users
);
  • useMemo, useCallback, React,memo는 컴포넌트의 성능을 실제로 개선할 수 있는(=실제로 불필요한 렌더링을 방지할 수 있는) 상황에서만 사용하는 것이 좋다.

useReducer

  • useReducer를 통해서도 상태를 관리할 수 있다. useReducer를 사용하면 컴포넌트에서 상태 업데이트 로직을 분리시킬 수 있다.
//사용 방법
//const [state, dispatch] = useReducer(reducer, initialState);

function reducer(state, action) {
  //state: 현재 상태, action: 업데이트를 위한 정보(주로 type 값을 가진 객체 형태)
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
  }
}

function Counter() {
  const [number, dispatch] = useReducer(reducer, 0);

  const onIncrease = () => {
    dispatch({ type: 'INCREMENT' });
  };

  const onDecrease = () => {
    dispatch({ type: 'DECREMENT' });
  };

  return (
    <div>
      <h1>{number}</h1>
      <button onClick={onIncrease}>+1</button>
      <button onClick={onDecrease}>-1</button>
    </div>
  );
}
  • useReducer vs useState
    컴포넌트에서 관리하는 상태 값이 여러 개가 되어서 구조가 복잡해진다면 (ex: 한 함수에서 여러 state의 setter를 호출하는 경우) useReducer를 사용하는 것이 좋을 수 있다.

커스텀 Hooks

  • 컴포넌트의 로직을 분리시켜 필요할 때 쉽게 재사용할 수 있다.

  • 만드는 방법 : useState, useEffect, useReducer, useCallback 등 기존 Hooks 를 사용하여 원하는 기능을 구현하고, 컴포넌트에서 사용하고 싶은 값들을 반환한다.

-useInputs 커스텀 Hook 을 useReducer를 사용해서 구현하기 : https://gist.github.com/velopert/e0d5a027f60a7368b2bb6f9277e3f742


Context API (전역 값 관리)

  • Context API를 사용해 프로젝트의 전역 값을 관리할 수 있다. 상태 뿐만 아니라 함수, 외부 라이브러리 인스턴스, DOM 등을 모두 전역으로 관리할 수 있다.

  • React.createContext() 함수를 사용해 새로운 Context를 생성한다.
    파라미터로는 Context의 기본값을 설정할 수 있다.

Context 객체 안에는 Provider라는 컴포넌트가 들어있는데, 이 컴포넌트를 통해 다음과 같이 Context의 값을 정할 수 있다.

export const AuthContext = React.createContext(null);

<AuthContext.Provider value={dispatch}>
	...
</AuthContext.Provider>
//dispatch를 Context 값으로 정해주어서 전역에서 dispatch를 사용할 수 있다. 

Provider로 감싸진 컴포넌트라면 어디에서든지 Context 값을 조회해서 사용할 수 있다.

Context 사용하기 :

import React, { useContext } from 'react';
import { AuthContext } from './App';

const User = () => {
	const dispatch = useContext(AuthContext);
    
    return (
    	<div onClick={() => {
        	dispatch({type: "TOGGLE" , id: user.id})}} />
    );
};

이렇게 useReducer와 Context API를 같이 활용하면,
Context API를 사용해 dispatch 를 어디서든지 조회할 수 있어서 코드 구조가 훨씬 깔끔해진다.


Immer (라이브러리)

  • 리액트에서 배열이나 객체를 업데이트할 때 불변성을 지키려면, 기존 배열/객체를 수정하지 않고 새로운 배열/객체를 생성해줘야 한다.
    대부분의 경우에서는 어렵지 않지만, 데이터의 구조가 복잡해지면 불변성을 지키면서 새로운 데이터를 생성해내는 코드가 조금 복잡해질 수 있다.

  • Immer를 사용하면, 상태를 업데이트할 때 불변성을 신경쓰지 않고 코드를 작성해도 Immer가 불변성 관리를 대신 해준다.


클래스형 컴포넌트

  • 클래스형 컴포넌트에는 render() 메소드가 꼭 있어야 한다.
    props를 조회할 때는 this.props로 접근해야 한다.
import React, { Component } from 'react';

class Hello extends Component {
  render() {
    const { color, name, isSpecial } = this.props;
  • defaultProps 설정은 함수형 컴포넌트와 동일한 방식으로 할 수도 있고,
    클래스 내부에 static 키워드와 함께 선언할 수도 있다.
class Hello extends Component {
  static defaultProps = {
    name: '이름없음'
  };
...
}

Hello.defaultProps = {
  name: '이름없음'
};
  • 커스텀 메서드 만들기
class Counter extends Component {
  handleIncrease() {
    console.log('increase');
  }

  handleDecrease() {
    console.log('decrease');
  }
  //...

이렇게 클래스 내부에 종속된 함수를 메서드라고 부른다. 클래스에서 커스텀 메서드를 만들 때는 보통 이름을 handle..로 짓는다.

  • 상태를 업데이트할 때에는 this.setState 라는 함수를 사용한다.
    this는 컴포넌트 인스턴스를 가리키는데, 커스텀 메서드 안에서 this를 조회해보면
    undefined가 나온다.
    이를 해결하려면 constructor에서 bind를 해주거나, 화살표 함수를 사용한다.
constructor(props) {
    super(props);
    this.handleIncrease = this.handleIncrease.bind(this);
    this.handleDecrease = this.handleDecrease.bind(this);
  }

  handleIncrease = () => {
    console.log('increase');
    console.log(this);
  };

  handleDecrease = () => {
    console.log('decrease');
  };

화살표 함수는 CRA로 만든 프로젝트에는 적용이 되어 있는 문법(class-properties 문법)이기 때문에 바로 사용할 수 있고,
그렇지 않은 경우에는 추가적인 설정이 필요하다.

  • 상태 선언하기 :
    클래스형 컴포넌트에서 상태를 선언할 때는 constructor 내부에서 this.state를 설정해주면 된다.
  constructor(props) {
    super(props);
    this.state = {
      counter: 0
    };
  }

클래스형 컴포넌트의 state 는 무조건 객체형태여야 한다.

class-properties 문법이 적용되어 있다면(ex: CRA로 만든 프로젝트) constructor를 사용하지 않고 다음과 같이 state를 설정할 수 있다.

class Counter extends Component {
  state = {
    counter: 0
  };
  • 상태 업데이트 :
    • 클래스형 컴포넌트의 state에서도 불변성을 유지하며 업데이트를 해야 한다.
    • setState에서도 useState와 마찬가지로 함수형 업데이트를 할 수 있다.
      함수형 업데이트는 보통 한 함수에서 setState를 여러 번에 걸쳐 해야 하는 경우에 유용하다.
      setState는 단순히 상태를 바꾸는 함수가 아니라, 상태를 바꿔달라고 요청하는 함수이다. 성능 상의 이유로 상태가 바로 업데이트되지 않고 비동기적으로 업데이트되기 때문이다.
      만약 상태 업데이트 후에 어떤 작업을 하고 싶다면, setState의 두 번째 파라미터에 콜백함수를 넣어주거나, 함수형 업데이트를 사용해야 한다.

LifeCycle Method (생명주기 메서드)

  • LifeCycle Method : 컴포넌트가 브라우저 상에 나타나고, 업데이트되고, 사라질 때 호출되는 메서드들. (+컴포넌트에서 에러가 났을 때 호출되는 메서드도 있음)
    라이프싸이클 메서드는 클래스형 컴포넌트에서만 사용할 수 있다.

  • 마운트 :

    • constructor : 컴포넌트 생성 시 가장 먼저 실행되는 메서드. 생성자 메서드.
    • getDerivedStateFromProps : props로 받아온 값을 state에 넣어주고 싶을 때 사용하는 메서드.
    • render : 컴포넌트를 렌더링하는 메서드.
    • componentDidMount : 컴포넌트의 첫 번째 렌더링 종료 후에 호출되는 메서드. 이 메서드가 호출되는 시점에는 컴포넌트가 화면에 나타난 상태이다.
      주로 DOM을 사용해야 하는 외부 라이브러리 연동이나, 해당 컴포넌트에서 필요로 하는 데이터 요청을 위한 axios, fetch 등 ajax 요청, 또는 DOM의 속성을 읽거나 직접 변경하는 작업을 한다.
  • 업데이트 :

    • getDerivedStateFromProps : 컴포넌트가 마운트될 때 뿐만 아니라 컴포넌트의 props나 state가 바뀌었을 때도 호출된다.
    • shouldComponentUpdate : 컴포넌트의 리렌더링 여부를 결정하는 메서드. 주로 최적화할 때 사용.
    • render
    • getSnapshotBeforeUpdate : 컴포넌트에 변화가 일어나기 직전 DOM 상태를 가져와 반환하는 메서드. 다음으로 발생하는 componentDidUpdate 에서 받아와서 사용할 수 있다. (DOM에 변화가 반영되기 직전에 DOM 속성을 확인하고 싶을 때 사용)
    • componentDidUpdate : 리렌더링이 끝나고 화면에 변화가 모두 반영된 후 호출되는 메서드. getSnapshotBeforeUpdate 에서 반환한 값을 조회할 수 있다.
  • 언마운트
    • componentWillUnmount : 컴포넌트가 화면에서 사라지기 직전에 호출된다.
      주로 DOM에 등록했던 이벤트를 제거하고, setTimeout 등을 clear하거나,
      외부 라이브러리 인스턴스를 제거한다. (=해당 라이브러리에 dispose 기능이 있는 경우 호출하는 것)

에러 핸들링

  • props 설정이 제대로 되지 않아 null/undefined 값이 들어오는 경우 (null값 참조)가 가장 많이 발생한다.
function User({ user }) {
  if (!user) {
    return null;
  }
  //...
  • 네트워크 요청을 통하여 나중에 데이터를 받아오게 되는 상황에서는
    이렇게 데이터가 없으면 null 을 보여주거나, 아니면 <div>로딩중</div>과 같은 결과물을 렌더링하면 된다.

  • props가 전달되지 않은 상황에서의 에러를 방지하기 위해 defaultProps 설정을 해줄 수도 있다.

Users.defaultProps = {
  onToggle: () => {
    console.warn('onToggle is missing!');
  }
};
  • 또는 실수로 props 전달을 깜빡했을 때 개발 단계에서 경고를 볼 수 있도록 PropTypes를 사용하거나 TypeScript, Flow를 사용해 관리할 수 있다.

  • componentDidCatch 메서드를 사용해 사전에 예외처리가 되지 않은 에러가 발생하는 경우를 핸들링할 수 있다. 그러나 componentDidCatch가 실제로 호출되는 일은 서비스에서 없어야 하는 게 맞다.
    그럼에도 발견하지 못한 에러가 있다면, componentDidCatch에서 errorinfo 값을 네트워크를 통해 다른 곳으로 전달해 확인할 수 있다.
    이를 위해 따로 서버를 만드는 것은 번거롭기 때문에 Sentry라는 서비스를 프로젝트에 적용하면 실시간으로 에러 정보를 확인할 수 있다.
    단, 배포 모드에서는 componentDidCatch로 잡은 에러는 Sentry에 전달이 되지 않으므로 따로 에러 바운더리로 처리해야 한다.

componentDidCatch(error, info) {
    console.log('에러가 발생했습니다.');
    console.log({
      error,
      info
    });
    this.setState({
      error: true
    });
    if (process.env.NODE_ENV === 'production') {
      Sentry.captureException(error, { extra: info });
    }
  }

process.env.NODE_ENV 값을 조회해 현재 환경(개발 환경/배포 환경)을 확인할 수 있다.
Sentry 연동을 해두면 버그 관리에 매우 도움이 되므로 연동해두는 것을 추천!

profile
💛💛 🖥🏐🛋🥗💵📖 💛💛
post-custom-banner

0개의 댓글