본문 바로가기

프로그래밍 공부내용/리액트(React)

useState와 useReducer의 인자에 대해서(about useState, useReducer arguments)

useState와 reducer의 효율성에 대해서 공부하다가,

 

리렌더링 시마다 값을 호출하는 문제에 대한 글을 봤다.

 

만약 state값을 초기화할때 number, string같은 값이 아니라 함수를 이용해서 생성하고 싶을 땐 어떻게 할까?

 

 

1. useState

import { useState } from 'react';

const initialMaker = () => {
  console.log('initialMaker Called');
  const init = 0;
  return init;
}

const TestComponent = () => {
  console.log('testComponent called');
  const [state, setState] = useState(initialMaker);

  const stateAdd1 = () => {
    setState((prev) => prev + 1);
  };

  return <button onClick={stateAdd1}>현재 state는 {state}입니다. </button>;
};

export default TestComponent;

이렇게 하면 리렌더시에는 호출을 안하고 첫 mount에만 함수를 실행하고 그 return값을 저장한다.

 

중요한것은   

const [state, setState] = useState(initialMaker());

처럼 함수를 호출해서 쓰면 안된다는 것이다.

 

더 정확하게 말하면 써도 되지만 효율성이 구리다.

 

무엇을 집어넣든 useState()안에 들어가는 값은 첫 한번만 state에 저장되는게 맞지만

(state자체가 오염되지는 않는다는 뜻임)

 

함수 호출식으로 넣어버리면 값을 저장하던 안하든 일단 호출은 하게 돼서 계속 호출해버린다.

 

아주 비효율적이다.

 

import { useState } from 'react';

const initialMaker = () => {
  console.log('initialMaker Called');
  const init = Math.random();
  return init;
}

const TestComponent = () => {
  console.log('testComponent called');
  const [state, setState] = useState(initialMaker());

  const stateAdd1 = () => {
    setState((prev) => prev + 1);
  };

  return <button onClick={stateAdd1}>현재 state는 {state}입니다. </button>;
};

export default TestComponent;

 

이렇게 보면 쉬운데, 계속 호출이 일어나지만 state가 random으로 update안되고 호출만 된다.
 
 

2. useReducer

 

reducer도 똑같이 생겨서 똑같을 것 같아서 실험해봤다.

 

const initialMaker = () => {
  console.log('initialMaker Called');
  const init = 0;
  return init;
};

const reducer = (state, action) => {
  console.log('reducer called');
  switch (action.type) {
    case 'add':
      return state + 1;
    default:
      return 0;
  }
};

const TestComponent = () => {
  console.log('testComponent called');
  const [state, dispatch] = useReducer(reducer, initialMaker);

  return <button onClick={() => dispatch({ type: 'add'})}>현재 state는 {state}입니다. </button>;
};

export default TestComponent;

 

이렇게 하면 mount시에만 호출...! 할것 같지만 에러를 준다.
 

 

 

 

값으로 주면 되긴한다... 아래와 같이..

const initialMaker = () => {
  console.log('initialMaker Called');
  const init = 0;
  return init;
};

const reducer = (state, action) => {
  console.log('reducer called');
  switch (action.type) {
    case 'add':
      return state + 1;
    default:
      return 0;
  }
};

const TestComponent = () => {
  console.log('testComponent called');
  const [state, dispatch] = useReducer(reducer, initialMaker());

  return <button onClick={() => dispatch({ type: 'add' })}>현재 state는 {state}입니다. </button>;
};

export default TestComponent;

이렇게 해서 값으로 건네주면 되지만, 그럼 리렌더링 될때마다 initialMaker도 호출해 버린다.

 

아까도 말햇듯이 효율성이 매우 안좋다.(리렌더할때마다 불러오기 때문에)

 

 

 

그래서 3번째 인자를 줄 수 있다. 리액트에서 다 만들어놨다.

const initialMaker = () => {
  console.log('initialMaker Called');
  const init = 0;
  return init;
};

const reducer = (state, action) => {
  console.log('reducer called');
  switch (action.type) {
    case 'add':
      return state + 1;
    default:
      return 0;
  }
};

const TestComponent = () => {
  console.log('testComponent called');
  const [state, dispatch] = useReducer(reducer, undefined, initialMaker);

  return <button onClick={() => dispatch({ type: 'add' })}>현재 state는 {state}입니다. </button>;
};

export default TestComponent;

이렇게 주면 mount시에만 initialMaker를 호출한다.

 

게다가 undefined말고 값을 전달해서 함수를 생성할 수 있다.

 

initialMaker(undefiend)를 실행한 값을 state에 초기값으로 저장하고 그 다음부터는 호출하지 않는다.