TIL_69_Hook

생활코딩

훅에서 clean up의 역할을 하는 것은?

// App.js
import React {useState, useEffect} from 'react';
import './App.css';

function App() {
  return (
    <div className="container">
      <h1>Hello World</h1>
      <FuncComp initNumber={2}></FuncComp>
      <ClassComp initNumber={2}></ClassComp>
    </div>
  );
}

let funcStyle = 'color:blue';
let funcId = 0;

function FuncComp(props) {
  let numberState = useState(props.initNumber);
  let number = numberState[0];
  let setNumber = numberState[1];

  //let dateState = useState((new Date().toString()));
  //let _date = numberState[0];
  //let setNumber = numberState[1];

  let [_date, setDate] = useState((new Date()).toString());

  //side effect
  useEffect(function(){
  console.log('%cfunc => useEffect (componentDidMount & componentDidUpdate)'+ (++funcId), funcStyle);
  document.title = number + ' : ' + _date;
  return function(){
  console.log('%cfunc => useEffect return (componentDidMount & componentDidUpdate)'+ (++funcId), funcStyle);
}
});
  
//useEffect (componentDidMount & componentDidUpdate) 2 가 호출 
// 그 다음에 랜덤을 클릭하면,
//render3 가 실행 -> 
//useEffect return (componentDidMount & componentDidUpdate) 4 가 실행되고 
//useEffect (componentDidMount & componentDidUpdate) 5가 실행.
//유즈 이팩트가 실행이 되고나서 다시 똑같은 유즈 이팩트가 실행되기 전에 
//뭔가 정리하는 작업이 필요하다면, return 값을 함수로 주면, 
//clean up의 역할을 한다. 
//유즈 이팩트가 실행이 될 때 초기화를 한 다음에 다시 한번 
//그 유즈 이팩트가 실행이 될 때 이전에 실행했던 것을 정리하는 역할-> 
//return 값에 있는 함수가 호출되는 것.

  console.log('%cfunc => render'+ (++funcId), funcStyle);

  return (
    <div className="container">
      <h2>function style component</h2>
      <p>Number : {number}</p>
      <p>Date : {_date}</p>
      <input type="button" value="random" onClick={
        function() {
          setNumber(Math.random());
        }
       }></input>
      <input type="button" value="date" onClick={
        function() {
          setDate((new Date()).toString());
        }
       }></input>
    </div>
  );
}

클래스 방식에서는 스테이트가 바뀔 때마다 이전의 props 와 이전의 state 값을 전달하여 두 개의 값이 다를 때만 작업을 처리하도록 했었다.

아래의 코드처럼.

componentDidUpdate(prevProps, prevState) {
  if (prevState.count !== this.state.count) {
    document.title = `You clicked ${this.state.count} times`;
  }
}

스테이트가 바뀔 때마다 인자로 이전의 프롭스 값과 이전의 스테이트 값을 전달 -> 이전의 값과 이후의 변경된 값을 비교해서 그 두 개가 다를 때만 어떠한 작업을 처리한다면 불필요한 처리를 하지 않을 수 있다. -> 즉 성능을 높일 수 있다.

이 과정을 Hook에선 어떻게 쓸 수 있을까?

// App.js
import React {useState, useEffect} from 'react';
import './App.css';

function App() {
  return (
    <div className="container">
      <h1>Hello World</h1>
      <FuncComp initNumber={2}></FuncComp>
      <ClassComp initNumber={2}></ClassComp>
    </div>
  );
}

let funcStyle = 'color:blue';
let funcId = 0;

function FuncComp(props) {
  let numberState = useState(props.initNumber);
  let number = numberState[0];
  let setNumber = numberState[1];

  //let dateState = useState((new Date().toString()));
  //let _date = numberState[0];
  //let setNumber = numberState[1];

  let [_date, setDate] = useState((new Date()).toString());

  //side effect
  useEffect(function(){
  console.log('%cfunc => useEffect number(componentDidMount & componentDidUpdate)'+ (++funcId), funcStyle);
  document.title = number;
//number 라는 state만 참조해서 작업을 하겠다는 뜻.
//즉 number의 값이 바뀌지 않았다면, 위 작업을 할 필요가 없다는 것. 
//number의 값이 바꼈을 때만 아래의 return 함수가 호출되도록 해보자.
    
  return function(){
  console.log('%cfunc => useEffect number return (componentDidMount & componentDidUpdate)'+ (++funcId), funcStyle);
}, [number]);
//number 배열안에 있는 원자들의 상태가 바꼈을 때만 첫번째 인자인 
//콜백함수가 호출이 되도록 약속되어있음.
//변한값에 대해서만 처리를 한다. -> 성능을 향상시킨다.
//return 함수 값은 clean up 할 때 쓰인다.

useEffect(function(){
  console.log('%cfunc => useEffect _date (componentDidMount & componentDidUpdate) '+(++funcId), funcStyle);
  document.title = _date;
  return function(){
    console.log('%Cfunc => useEffect _date return (componentDidMount & componentDidUpdate)  '+(++funcId), funcStyle);
  }
}, [_date]);
 
  console.log('%cfunc => render'+ (++funcId), funcStyle);

  return (
    <div className="container">
      <h2>function style component</h2>
      <p>Number : {number}</p>
      <p>Date : {_date}</p>
      <input type="button" value="random" onClick={
        function() {
          setNumber(Math.random());
        }
       }></input>
      <input type="button" value="date" onClick={
        function() {
          setDate((new Date()).toString());
        }
       }></input>
    </div>
  );
}

컴퍼넌트 디드 마운트만 하고싶을 때?

  useEffect(function(){
    console.log('%cfunc => useEffect (componentDidMount) '+(++funcId), funcStyle);
  document.title = number;
  return function(){
    console.log('%cfunc => useEffect return (componentWillUnMount) '+(++funcId), funcStyle);
  }
}, []};

위 코드처럼 빈배열을 넣어주면 된다.
빈 배열을 넣어주게 되면 1회만 실행이 되고 그 이후에는 실행이 되지 않는다.

콘솔을 확인해보면 componeneDidMount가 1회만 호출이 되고 더이상 호출이 되지 않은 것을 확인할 수 있다.

나의 이해를 돕기 위해 추가


render 가 되고 useEffect return 함수가 먼저 실행이 되면서 clean up을 한 뒤 useEffect number 가 실행된 것을 확인할 수 있다.

_date 함수는 date를 클릭하지 않았기 때문에 실행되지 않음.

[number] 배열 안에 있는 'number' 가 상태가 변해야만 useEffect 함수가 실행이 되고
return 함수가 있다면 useEffect 가 실행되기 전에 return 함수가 먼저 실행이 되면서 clean up을 한다.


코드를 보자.
주석처리된 return function은 clean up 역할을 하고 그 아래에 [number]가 상태가 바뀌면 실행이 되도록 하는 것.

좋은 웹페이지 즐겨찾기