티스토리 뷰

React Hooks

Hooks는 React v16.8에 추가된 기능입니다.

이전 버전에서 함수 컴포넌트에서는 사용할 수 없던 class 컴포넌트의 Life Cycle메서드(componentDidMount, componentWillUnmount, componentDidUpdate)와 동일한 기능을 사용할 수 있도록 고안된 기술입니다.

Closure

함수가 속한 Lexical scope를 기억하여 해당 함수밖에서 이 scope에 접근할 수 있게 하는 기능.

react hooks를 이해하기 전에 먼저 closure를 알고 있어야 합니다. closure를 한줄로 정의하면 위와 같습니다만, 잘 이해하기 위해 직접 사용해볼 필요가 있습니다. 여기서는 React hooks를 직접 만들어보며, closure를 사용해보고 hooks 메커니즘을 이해하고자 합니다.

useState

React useState는 함수 컴포넌트에서 상태를 가질 수 있도록 해주는 Hook 입니다.

useState는 length가 2인 배열을 반환하며 0번째 index의 원소는 컴포넌트가 가질 상태, 1번째 index의 원소는 0번째 값의 상태를 변경하는 함수입니다.

function render(){ //... }function useState(initState) {
  // 새로운 상태 정의
  const state = initState;  const setState = (newState) => {
    // 상태 갱신
    state = newState;
    // 컴포넌트 Rerender를 진행하는 render()함수
    render();
  };  return [state, setState];
}

useState함수 내부를 간단하게 구현해보았습니다.

  1. parameter로 초기화 value를 받습니다.
  2. useState 내부에 state 변수가 있고, initVal을 할당합니다.
  3. useState함수 내부에는 setState함수가 있고 새로운 상태를 받아서 state를 갱신합니다.
  4. 변수 state와 함수 setState를 반환합니다.

위에서 정의한 useState함수는 React Hooks와 비슷한 패턴으로 작성할 수 있습니다. 실제로 React컴포넌트에서 주로 아래와 같이 사용됩니다.

const [value, setValue] = useState(0);

위의 코드는 단순하게 표현한 함수로 실제로 React의 useState와 동일하게 작동하지는 않습니다.

state 변수는 useState함수 내부에 존재하므로, useState 내부에서 초기화 한 변수는 함수 실행 시 한번만 사용되고 사라지는 휘발성으로 작동합니다.

state변수의 내용을 유지하기 위해 state변수를 useState 외부에 둘 필요가 있습니다.

let state;
function useState(initState) {
  state = initState  const setState = (newState) => {
    state = newState;
    render();
  };  return [state, setState];
}

위와 같이 작성하면 useState 실행이 완료되어도 state에 초기화한 변수는 보존됩니다.

여기서 closure 개념을 이용할 수 있습니다. 이해하기 쉽도록 코드로 먼저 표현해보겠습니다.

const React = (function () {
  let state;
  
  function render() {
    // ...
  }function useState(initState) {
    state = initState;
    const setState = (newState) => {
      states = newState;
      render();
    };
    return [state, setState];
  }  return {
    useState,
    render,
  };
})();

여기서 React라는 함수 내 state변수, useState함수가 있고 React는 useState를 반환합니다.

React는 클로저를 형성하고 있고, React 외부의 어떤 컴포넌트에서 useState를 이용하여 React state에 접근할 수 있습니다.

즉 외부에서 React의 state 변수를 사용할 수 있게 되는 형태입니다. 위의 코드에서는 useState에서 state를 반환함으로써 state값을 직접적으로 알 수 있습니다.

좀더 정확한 useState기능을 위하여 위의 코드를 다시 고쳐보겠습니다.

위의 코드에서는 , 하나의 변수에만 값을 관리하기 때문에, 여러개의 상태를 관리할 수 없다는 문제가 있습니다.

그래서 state는 하나의 변수가 아닌 배열로 만들어주면 여러개의 상태를 관리할 수 있습니다.

state를 배열로 두고, state의 배열을 가리킬 index가 필요합니다. index를 가지고 있어야 다음 상태를 가리킬 수 있습니다.

const React = (function () {
  let state = [];
  let stateKey = 0;
  
  function useState(initState){
    const { states, stateKey: key } = _this;
    if (states.length === key) states.push(initState);
    const state = states[key];
    const setState = (newState) => {
      states[key] = newState;
      render();
    };
    _this.stateKey += 1;
    return [state, setState];
  }  return {
    useState,
    render,
  };
})();

useEffect

useEffect는 React 함수 컴포넌트에서 class컴포넌트의 Life Cycle를 사용할 수 있게 해주는 hook입니다.

useEffect는 첫번째 parameter로 함수를 받고, 두번째 parameter로 배열을 받습니다. 두번째 parameter는 deps array라고 합니다.

deps array에 있는 내용과 React의 state와 비교하여 변경된 다른 내용이 있다면 callback함수를 실행시킵니다.

const React = (function () {
  let state = [];
  let stateKey = 0;
  
  function render() {
    // ...
  }function useState () {
    // ...
  }function useEffect(callback, depArray) {
    // deps array가 없다면 callback 함수를 실행
    const hasNoDeps = !depArray;
    // deps array와 React states를 비교하여 바뀐 내용이 있다면 
    const deps = states[stateKey];
    const hasChangedDeps: boolean = deps ? !depArray?.every((el: any, i: number) => el === deps[i]) : true;
    if (hasNoDeps || hasChangedDeps) {
      callback();
      hooks[stateKey] = depArray;
    }
    _this.stateKey++;
  }
  return {
    useState,
    useEffect,
    render,
  };
})();

React에서는 deps array가 없을 경우(undefined) 첫번째 parameter로 들어오는 함수를 조건 없이 실행시킵니다.

그리고 deps array가 있을 경우 React의 state와 비교하여 바뀐 내용이 있다면 callback함수를 실행시킵니다.

참조

https://www.youtube.com/watch?v=KJP1E-Y-xyo

https://rinae.dev/posts/getting-closure-on-react-hooks-summary

'front-end > react' 카테고리의 다른 글

Redux 구현  (0) 2023.05.03
가상 돔, Virtual DOM  (0) 2023.05.03
Redux 구현  (0) 2022.02.16
React Diffing algorithm2 - Fiber  (0) 2021.12.27
React Diffing algorithm1 - Heuristics algorithm  (0) 2021.12.13
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/06   »
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
글 보관함