react hooks api를 js로 바꿔보기

qoqo_mi·2024년 3월 27일

React

목록 보기
1/3

useState hooks 동작 방식

useState는 함수 컴포넌트 내부에서 상태를 정의하고, 이 상태를 관리할 수 있게 하는 훅이다.

useState의 동작 조건

  1. 컴포넌트가 다시 실행되어도 count의 값은 초기화되지 않고 유지된다.
    useState를 실행하면 첫 번째 인자는 state를 반환하고, 두 번째 인자는 state를 변경하는 setState를 반환한다. 그리고 setState를 실행하면 render가 실행된다.
    useState를 실행하면 내부에서 state를 정의하고, setState를 실행하면 내부에 선언된 state를 변경할 것이다. -> 함수가 실행될 때마다 initState로 초기화된다.
function useState(initState) {
  let state = initState; // state를 정의한다. 함수가 실행될 때마다 initState로 초기화된다. 
  const setState = (newState) => {
    state = newState; // 새로운 state를 할당한다.
    render(); // render를 실행한다.
  }
  return [ state, setState ];
}

따라서 state의 값은 내부가 아닌 외부에서 관리해야 한다.

  let state = undefined; // state는 외부에서 관리되어야 한다. 
function useState(initState) {
	if(state ===undefined){
      state = initState; // state에 값이 없는 경우에만 초기화 진행
    }
  const setState = (newState) => {
    state = newState; // 새로운 state를 할당한다.
    render(); // render를 실행한다.
  }
  return [ state, setState ];
}
  1. useState와 component가 여러개인 경우
  • 위 코드처럼 한 개의 state만 관리한다면 useState와 Component가 여러개라면 한 개의 state변수로 두 개의 state를 관리하기 때문에 두 state에서는 동일한 값을 보여주게 된다. -> 외부의 state개수를 useState가 실행되는 횟수만큼 만든다.
let states = [];
  let currentIndex = 0;

  const useState = (initState) => {
    const index = currentIndex;
    // states의 내부 데이터 초기값 설정
    if (states.length === index) {
      states.push(initState);
    }
    // state : 초기값을 담은 변수
    const state = states[index];

    const setState = (newState) => {
      // setState 내부에서는 newState가 변환이 없는 경우 실행 중지
      if (states[index] === newState) {
        return;
      }
      // 새로운 값으로 변경되는 경우 newState로 업데이트하고 callback() 실행
      states[index] = newState;

      callback();
    };

    currentIndex += 1;

    return [state, setState];
  };
 const resetContext = () => {
    currentIndex = 0; // 다시 0부터 접근할 수 있도록 값을 초기화 해야 한다.
  };

useMemo의 동작 방식

useMemo의 정의

useMemo는 리액트에서 컴포넌트의 성능을 최적화 하는데 사용되는 훅이다.

useMemo에서 memo는 memoization을 뜻하는데 그대로 해석하면 '메모리에 넣기'라는 의미이며 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 반복 수행을 제거하여 프로그램 실행 속도를 빠르게 하는 기술이다.

쉽게 말해 동일한 값을 변환하는 함수를 반복적으로 호출해야한다면 처음 값을 계산할 때 해당 값을 메모리에 저장해 필요할 때마다 다시 계산하지 않고 메모리에서 꺼내서 재사용하는 것

useMemo의 렌더링

리액트에서 함수형 컴포넌트는
렌더링 ➡️ 컴포넌트 함수 호출 ➡️ 모든 내부 변수 초기화
순서를 거친다.
useMomo훅을 사용하면
렌더링 ➡️ 컴포넌트 함수 호출 ➡️ memoize 된 함수 재사용
하는 순서를 거친다.

이런 방식으로 처음에 계산된 값을 메모리에 저장해 컴포넌트가 계속 렌더링되어도 함수를 재호출하지 않고 메모리에 저장되어있는 계산된 값을 가져와 재사용할 수 있게 해준다.

useMemo의 구조

useMemo를 Js로 변경하여 구현해본 코드이다.
1. useMemo에 들어온 값은 초기값이 없는 경우, 그리고 초기값과 새로 업데이트된 값이 일치하지 않는 경우에 값은 변경된다.

  const isSameValue = (a, b) => {
    const max = Math.max(a.length, b.length);
    for (let i = 0; i < max; i += 1) {
      if (a[i] === b[i].refs[0]) {
        return true;
      }
      return false;
    }
  };

  const useMemo = (fn, refs) => {
    const index = currentIndex;

    // 최초시작 혹은 디펜던시가 변경된 경우
    if (states[index] === undefined || !isSameValue(refs, states)) {
      states[index] = { result: fn(), refs };
    }
    return states[index].result;
  };

회고

  • 사실 useState는 동작에 대해 어느정도 이해하고 있었지만 useMemo같은 경우는 메모리제이션에 대한 개념만 있을 뿐 매번 useMemo를 난무했다. 이런 부분들이 어느정도 코드에 불필요하거나 오히려 노이즈를 일으키는 요인이 되기도 한다.
  • 이런 부분들을 알게 된 이후 사용되는 코드에서 무분별하게 사용되는 useMemo를 리팩토링하게 되었다.

0개의 댓글