Hooks

taehyung·2023년 10월 5일

React.js

목록 보기
9/24

다들 즐거운 한가위 보내셨나요? 풍요로운 명절동안 살만 디룩디룩찌고 공부는 잠시 손을 놓았습니다. 새로운 마음으로 다시 시작합니다!

useState

가장 기본적인 Hook, 함수형 컴포넌트에서 동적인 값을 상태 라고 칭합니다. useState는 이러한 상태를 관리합니다.

const Hooks = () => {
	const [var, setVar] = useState('value');
	//구조분해할당을 이용해 [기본값, 기본값을 관리하는 함수] 로 	설정할 수 있습니다.
  	//var = 'value'
	//setVar = var의 값을 업데이트해주는 함수
	return (
		<button onClick={()=>{setVar("setValue")}}></button>
	);
}
export default Hooks;

useEffect

리액트 컴포넌트의 렌더링 과정을 분기처리하여 원하는 타이밍에 적절한 함수를 실행하고 싶을 때 사용합니다.

const Hooks = () => {
	useEffect( () => {
	
      ...code; //마운트시 작동할 코드

      return () => { //언마운트시 작동할 코드

        ...code

      },[deps]} //빈배열일시 첫마운트에만 작동
                //특정 값 업데이트시 작동하려면 배열에 요소로 옵저빙 할 변수 입력
	)
}
export default Hooks;

주의
useEffect 내부에서 사용하는 상태, Props가 있다면 반드시 deps 에 넣어주어야 합니다. 규칙입니다.

넣지 않으면, useEffect 가 실행될 때 다른곳에서 변경된 상태, Props의 최신 값을 반영하지 못합니다.

다양한 분기점에 useEffect 사용하기

	//렌더링시 매 번 실행, 기본값
	useEffect(() => { console.log("complete") });

	//첫 렌더링에만 실행, 2번째 파라미터에 빈 배열
	useEffect(() => { console.log("complete"),[] });

	//특정 값의 업데이트마다 실행, 2번째 파라미터에 원하는 특정 값을 가진 배열 ( useState, props 등 )
 	useEffect(() => { console.log("complete"),[value] });

	//컴포넌트 언마운트시 실행, useEffect가 return 하는 함수가 언마운트 직전 실행됩니다.
    useEffect(() => {
      console.log("complete");
      return() => {
        console.log('cleanUp');
      }
    });
	

useReducer

useState 와 같이 상태를 관리하는 Hook 이며, 차이점은 useReducer 를 사용하면 상태관리 로직을 컴포넌트에서 분리할 수 있습니다.
useState 에서의 setState(...code) 와같은 로직 말이죠.

useReducer의 기본형태

1. function reducer(state,action){
	switch(action.type){
      case 'type':
      	return state+'입니다.';
    }
}

const Hooks = () => {
	2. const [var, dispatch] = useReducer(reducer,'value');
  	3. const func = () => {
    	dispatch({type:'type'}) // 어떠한 값도 파라미터로 사용이 가능합니다. ex) e.target , 문자열, 숫자 등
    }
    
    <button onClick = { func }></button>
  
}
  1. reducer 함수 : 현재의 상태값, 액션을 인자로 받아서 업데이트할 상태를 결정짓는 함수
  2. useReducer : 첫번째 인자로 reducer 함수를 넣고, 두번째 인자로 기본값을 설정합니다.
    var = value, dispatch = reducer 와같이 바인딩됩니다.( 구조분해할당 )
  3. dispatch : dispatch 함수는 인자로 객체를 넣어주며 ( 꼭 객체 아니어도됨 ) 통상적으로 type 속성을가진 객체를 넘겨줍니다.

Counter 예제

import React, { useReducer } from 'react';

function reducer(state, action) {
  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>
  );
}

export default Counter;

이것을 보면서 저는 한가지 의문점이 들었습니다.
dispatch() 함수는 reducer 함수를 실행시켜주는데, 인자로 객체 하나만 넘겨주었습니다.

그렇다면 자연스럽게 state 파라미터에 객체가 들어가야하는게 아닌가하는 생각이요.. 상태를 관리할 number 변수는 dispatch에게 알려주지 않았거든요..

아마도 useReducer를 사용하여 상태를 관리할 변수를 만들 때 dispatch 함수가 number 변수를 미리 바인딩 하거나, reducer 함수에게 미리 바인딩하거나 둘 중 하나인것 같습니다.


useMemo

컴포넌트 내부에서 발생하는 연산을 최적화할 때 사용합니다.
특정 값을 재사용하고 싶을 때 사용합니다.

렌더링 과정에서 지정한 값의 변화를 감지, 변했다면 연산을 실행, 변하지 않았다면 이전에 값을 사용합니다.

입력상자에 숫자를 입력하고 등록버튼을 누르면 리스트업되면서 평균값을 구해주는 예제입니다.


import React, { useState } from "react";

const getAverage = (number) => {
  console.log("평균값 계산 중 ...");
  if (number.length === 0) return 0;
  const sum = number.reduce((a, b) => {
    return a + b;
  });
  return sum / number.length;
};

const Average = () => {
  const [list, setList] = useState([1]);
  const [number, setNumber] = useState("");

  const onChange = (e) => {
    setNumber(e.target.value);
  };
  const onInsert = (e) => {
    const nextList = list.concat(parseInt(number));
    setList(nextList);
    setNumber("");
  };

  return (
    <div>
      <input value={number} onChange={onChange}></input>
      <button onClick={onInsert}>등록</button>
      <ul>
        {list.map((v, i) => (
          <li key={i}>{v}</li>
        ))}
      </ul>
      평균값 : {getAverage(list)}
    </div>
  );
};

export default Average;

문제
등록버튼을 눌렀을 때만 getAverage가 실행되게 하고싶은데 입력상자에 값을 입력할때도 작동하죠? onChange 함수가 set 함수를 사용하여 컴포넌트가 리렌더링되기 때문입니다.

useMemo Hook를 이용하면 해결할 수 있습니다.

import React, { useMemo, useState } from "react";

const getAverage = (number) => {
  console.log("평균값 계산 중 ...");
  if (number.length === 0) return 0;
  const sum = number.reduce((a, b) => {
    return a + b;
  });
  return sum / number.length;
};

const Average = () => {
  const [list, setList] = useState([1]);
  const [number, setNumber] = useState("");

  const onChange = (e) => {
    setNumber(e.target.value);
  };

  const onInsert = (e) => {
    const nextList = list.concat(parseInt(number));
    setList(nextList);
    setNumber("");
  };

  const avg = useMemo(() => getAverage(list), [list]);

  return (
    <div>
      <input value={number} onChange={onChange}></input>
      <button onClick={onInsert}>등록</button>
      <ul>
        {list.map((v, i) => (
          <li key={i}>{v}</li>
        ))}
      </ul>
      평균값 : {avg}
    </div>
  );
};

export default Average;

주의
useMemo 내부에서 사용하는 상태, Props가 있다면 반드시 deps 에 넣어주어야 합니다. 규칙입니다.

넣지 않으면, useMemo 가 실행될 때 다른곳에서 변경된 상태, Props의 최신 값을 반영하지 못합니다.


useCallback

함수를 재사용하기위해 사용합니다.

const test = useCallback(func(),[])
첫번째 파라미터 = 생성하고 싶은 함수
두번째 파라미터 = 배열안에 지정된 값이 변경되면 함수 생성

주의
useCallback 내부에서 사용하는 상태, Props가 있다면 반드시 deps 에 넣어주어야 합니다. 규칙입니다.

넣지 않으면, useCallback 가 실행될 때 다른곳에서 변경된 상태, Props의 최신 값을 반영하지 못합니다.

import React, { useMemo, useState } from "react";

const getAverage = (number) => {
  console.log("평균값 계산 중 ...");
  if (number.length === 0) return 0;
  const sum = number.reduce((a, b) => {
    return a + b;
  });
  return sum / number.length;
};

const Average = () => {
  const [list, setList] = useState([1]);
  const [number, setNumber] = useState("");

  const onChange = useCallback( (e) => {
    setNumber(e.target.value);
  },[]) // 컴포넌트가 처음 렌더링될때만 함수 생성
 
  
  const onInsert = useCallback((e)=>{
    const nextList = list.concat(parseInt(number));
    setList(nextList);
    setNumber("");
  },[number, list]); //number혹은 list가 변경됐을 때만 함수 생성
  
  const avg = useMemo(() => getAverage(list), [list]);

  return (
    <div>
      <input value={number} onChange={onChange}></input>
      <button onClick={onInsert}>등록</button>
      <ul>
        {list.map((v, i) => (
          <li key={i}>{v}</li>
        ))}
      </ul>
      평균값 : {avg}
    </div>
  );
};

export default Average;

정리

  • useState : 컴포넌트 내에 동적인 값을 관리한다. 상태관리
  • useEffect : 컴포넌트 마운트, 리렌더링시 분기를 나누어 원하는 타이밍에 원하는 함수를 실행할 수 있다.
  • useReducer : useState와 같이 동적인 값을 관리하는 상태관리 Hook 이다. 가장 큰 차이점은 비즈니스 로직을 분리할 수 있다는 점이다.
  • useMemo : 컴포넌트 리렌더링시 반복되는 연산을 막을 수 있어 최적화에 사용된다.
  • useCallback : 컴포넌트 리렌더링시 반복되는 함수의 선언과 실행을 막을 수 있어 최적화에 사용된다.
  • useRef : 컴포넌트 내에 JSX 태그에 직접적인 접근이 가능하다. 또한 컴포넌트가 리렌더링되어도 변하지않는 값을 관리할 수 있다.
profile
Front End

0개의 댓글