바닥코딩

Hooks 본문

React JS/React 기초

Hooks

개발공부개발공부 2022. 9. 22. 22:43

 Hooks는 리액트 v16.8에 새로 도입된 기능으로 함수 컴포넌트에서도 상태관리, 렌더링 직후 작업을 설정하는 기존에 되지 않았던 기능들을 지원하게 됐습니다.

useState

 가장 기본적이며 이미 함수 컴포넌트에서 여러번 사용해 봤던 hook입니다.  간단하게 코드로 살펴보자면

import React, { useState } from 'react'

const Counter = () => {

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

  return (
    <div>
      <p>
        현재 값은 <b>{value}</b> 입니다.
      </p>
      <button onClick={() => setValue(value +1)}>+</button>
      <button onClick={() => setValue(value -1)}>-</button>
    </div>
  )
};

export default Counter;

 위 코드르 생성한 코드는 브라우저 상에서 

위와 같은 컴포넌트를 생성하게 됩니다. 위에서 + - 버튼을 각각 누르면 현재 값에서 표시되는 값이 각각 +1 -1 이 되게 되는데 코드에서 알 수 있든 이 역할은 setValue에서 실행되게 됩니다. 정리하자면

 const [value, setValue] = useState(0); // [state, state변경 함수명] = useState(초기값)

useState는 value라는 state를 생성하고 초기값으로 0을 만들어 주며 , setValue를 통해 state의 상태를 관리합니다.

 

useEffect

 useEffect 는 리액트 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 설정할 수 있는 hook 입니다 일전 포스팅 했던 

https://dkkim2318.tistory.com/97

 

라이프사이클 메서드

라이프사이클 메서드  리액트에는 총 9가지의 라이프사이클 메서드가 존재합니다. 또한 이는 크게 3가지, 마운트 / 업데이트 / 언마운트 카테고리로 나뉩니다 .  첫번째 마운트(Mount) 는 DOM 객체

dkkim2318.tistory.com

라이프사이클 메서드에 componentDidMount 와 componenetDidUpdate를 합친 형태로 볼 수 있습니다.

코드로 살펴보자면 

import React, { useEffect, useState } from 'react'

 const Info = () => {
    const [name,setName] = useState ("");
    const [nicName , setNicName] = useState ("");

    const onChangeName  = e  => {
        setName(e.target.value);
    };

    const onChangeNicName = e => {
        setNicName(e.target.value);
    };

    useEffect(() => {  //마운트가 실행될 때만 호출 
        console.log("It will be start when Mount");
    },[]);
    
    useEffect(()=> { // 특정값이 업데이트 될 때만 호출
        console.log(name )
    },[name]);

    useEffect(()=>{
        console.log("effect");
        console.log(name);
        return () => {
            console.log("clean up");
            console.log(name);
        }
    },[name]);

  return (
    <div>
        <div>
            <input value={name} onChange = {onChangeName }/>
            <input value={nicName} onChange = {onChangeNicName }/>
        </div>
        <div>
            <b>이름 : </b><span>{name}</span>
        </div>
        <div>
            <b>닉네임 : </b><span>{nicName}</span>
        </div>
    </div>
  )
}

export default Info;

useEffect의 두번째 인자값에 빈 배열을 넣었을 경우와 특정 state를 넣었을 경우로 분류할 수 있는데, 

 

생성된 컴포넌트와 콘솔창을 통해 특정 마운트 될때와  특정 state 가 업데이트 될 때 실행되는 것을 확인할 수 있습니다.

 

useReducer

useReducer 는 useState 보다 더 다양한 컴포넌트를 상황에 따라 다른 값으로 업데이트를 해주고 싶을 때 사용할 수 있는 hook 입니다. 코드를 통해 알아보면

import React, { useReducer } from 'react';

function reducer(state, action){
    //actionn.type에 따라 다른 작업 수행 
    switch(action.type){
        case "INCREMENT" : 
            return{value : state.value + 1};
        case "DECREMENT" : 
            return{value : state.value - 1};
        default : 
         return state;
    }
}

const Reducer = () => {
    const [state, dispatch] = useReducer(reducer, {value :0});
    return (
        <div>
            <p>
                현재 카운터 값은 <b>{state.value}</b>
            </p>
            <button onClick={()=> dispatch({type : 'INCREMENT' })}>+1</button>
            <button onClick={()=> dispatch({type : 'DECREMENT'})}>-1</button>
        </div>
    );
};

export default Reducer;

useReducer의 첫 인자는 리듀서 함수를 넣고 두번째 인자에는 해당 리듀서의 기본 값을 넣어줍니다. 이 hook을 사용하면 state 값과 dispatch 함수를 받아오게 되는데 여기서 state는 현재 상태를 의미하고 dispatch는 액션을 발생시키는 함수이빈다 함수 안에 파라미터로 액션 값을 넣어주면 리듀서 함수가 실행되게 됩니다.

 

useMemo

 useMemo를 사용하면 함수 컴포넌트 내부에서 발생하는 연산을 최적화 할 수 있습니다.  코드를 통해 알아보면

import React, { useState } from 'react';

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

const UseMemo = () => {

    const[list, setList] = useState([]);
    const[number, setNumber] = useState('');

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

    const pressEnter = e => {
        if(e.key == 'Enter'){
            onInsert();
        }else{
            return false;
        }
    }

    return (
        <div>
           <input value= {number} onKeyDown={pressEnter} onChange = {onChange}/> 
           <button onClick={onInsert} >평균값 계산</button>
           <ul>
            {list.map((value, index) => (
                <li key={index}>{value}</li>
            ))}
            </ul>
            <div>
                <b>평균값:</b>{getAverage(list)}
            </div>
        </div>
    );
};

export default UseMemo;

위코드는 브라우저 내에서 입력한 숫자들의 평균값을 생성하는 컴포넌트를 생성합니다

 

여기서 만약 useMemo를 사용하지 않았다면 평균값  옆  {avg}는 {getAverage(list)}가 되었을 것입니다 그렇지만 useMemo를 사용하면 위와 같이 연산을 최적화 하는 것이 가능합니다.

 

useCallback

 useCallback은 useMemo와 상당히 비슷한 함수입니다. 다른점이 있다면 주로 렌더링 성능을 최적화 하는 경우에서 사용된다는 것인데 코드를 통해 알아보겠습니다.

import React, { useCallback, useMemo, useState } from 'react';

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

const UseCallback = () => {
    
    const [list, setList] = useState([]);   
    const [number, setNumber] = useState('');

    const onChange = useCallback(e=>{
        setNumber(e.target.value);
    }, []);

    const onInsert = useCallback(()=>{
        const nextList = list.concat(parseInt(number));
        setList(nextList);
        setNumber('');
    }, [number, list]);


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

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


export default UseCallback;

 이전 useMemo때 작성했던 코드의 비슷한 코드 입니다. onChange 함수와 onInset 함수 부분이 useCallback hook을 사용해 바뀌었다는점인데, useCallback의 첫 인자에는 생성하고 싶은 함수를 두 번째 인자에는 배열을 넣어줍니다. 이는 어떤 값이 바뀌었을 떄 함수를 새로 생성해야 하는지 명시해 줍니다.

 위와 같이 onChange 처럼 빈 배열을 넣어주면 컴포넌트가 렌더링될 떄 만들었던 함수를 계속하여 재사용하게 되며, onInsert 처럼 number, list등 파라미터들을 넣어주면 인풋 내용이 바뀔 땜난 새로 만들어진  함수를 사용하게 됩니다.

 

useRef

useRef는 함수 컴포넌트에서 ref를 쉽게 사용할 수 있도록 해줍니다.

import React, { useCallback, useMemo } from 'react';

const getAverae = numbers => {
    console.log ('평균값 계산 중 ...');

    if(numbers.length === 0) return 0;

    const sum = numbers.reduce((a,b) => a +b);
    return sum /numbers.length;
}

const UseRef  = () => {

    const [list, setList] = useState([]);
    const [number, setNumber] = useState('');
    const inputEL = useRef(null);

    const onChange = useCallback(e => {
        setNumber(e.target.value);
    },[]);

    const onInsert = useCallback(e => {
        const nextList  = list.concat(parseInt(number));
        setList(nextList);
        setNumber('');
        inputEl.current.focus();
    },[number, list]);

    const avg = useMemo(() => getAverae(list),[list]);
    return (
        <div>
         <input value={number} onChange = {onChange} ref={inputEl}></input>
         <button onClick={onInsert}></button> 
        <ul>
           {list.map((value, index) => (
             <li key={index}>{value}</li>
           ))} 
        </ul>
        <div>
            <b>평균값 : </b> {avg}
        </div>
        </div>
    );
};

export default UseRef ;

해당 코드는 등록 버튼을 눌렀을때 포커스가 인풋 쪽으로 넘어가도록 작성한 코드입니다.  위와 같이 useRef를 사용하면 useRef를 통해 만든 객체 안의 current 값이 실제 엘리먼트를 가르키게 됩니다.

'React JS > React 기초' 카테고리의 다른 글

라우팅 & SPA  (0) 2022.11.03
라이프사이클 메서드  (0) 2022.08.30
이벤트 핸들링  (0) 2022.03.25
컴포넌트 활용하기(state)  (0) 2022.03.25
컴포넌트 활용하기(props)  (0) 2022.03.24