React Hooks 사용하기(2)_useReducer, useMemo

호박쿵야·2021년 12월 1일
0

react

목록 보기
2/7
post-thumbnail

useReducer

useReducer는 useState보다 더 다양한 컴포넌트 상황에 따라 다양한 상태를 값으로 업데이트해 주고 싶을 때 사용하는 hook이다. reducer는 현재 state, 그리고 업데이트를 위해 필요한 정보를 담은 action 값을 전달받아 새로운 상태를 반환하는 함수이다.

function reducer(state, action){
  return {...}
}

새로운 상태를 만들 때는 반드시 불변성을 지켜주어야한다.

import React, {useReducer} from 'react'

function reducer(state, action){
    switch(action.type){
        case `INCREMENT`:
            return {value : state.value+1}
        case `DECREMENT`:
            return {value : state.value-1}
        default :
            return state

    }
            
}

const Counter = ()=> {
    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 Counter

useReducer(reducer, {value:0}) 부분을 보면 첫 번째 파라미터로는 reducer 함수를, 두 번째 파라미터에는 해당 reducer의 기본 값을 넣어주었다. 이때 hook을 사용하며 state와 dispatch 함수를 받아온다.
state : 현재 가르키고 있는 상태
dispatch : action을 발생시키는 함수 -> dispatch(action) 호출을 해주면 리듀서 함수가 호출된다.

reducer의 가장 큰 장점은 컴포넌트 업데이트 로직을 컴포넌트 바깥으로 빼낼 수 있다는 것.

input value 상태 값 관리하기

import {useReducer} from "react"

function reducer(state, action){
    return {
        ...state,
        [action.name]:action.value
    }
}

const Info =()=>{

    const [state, dispatch] =useReducer(reducer, {name:'', nickname:''})
    const {name, nickname} = state 
   

    const onChange =(e)=>{
      dispatch(e.target)
    }
  
    return(

        <div>
            <>
            <input name="name"value={name} onChange ={onChange}/>
            <input name="nickname" value={nickname} onChange ={onChange}/>
            </>
            <div>
            <b>이름 : </b> {name}
            </div>
            <div>
            <b>닉네임 : </b> {nickname}
            </div>
        </div>
    )
}
export default Info;

useReducer에서의 액션은 그 어떤 값도 사용 가능하다. 위 예제는 이벤트 객체가 지니고 있는 e.target 값을 액션 값으로 사용했다.
console.log( e.target ) 출력 값 👉 <input name="name" value ="호박쿵야">

useMemo

useMemo를 사용하면 함수형 컴포넌트 내부에서 발생하는 연산을 최적화할 수 있다.

리스트에 숫자를 추가하면 추가된 숫자들의 평균을 보여주는 함수형 컴포넌트를 작성해보자.

import {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 Average = ()=>{
    const [list, setList] = useState([]);
    const [number, setNumber] = useState('');

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

    return(
        <div>
            <input value ={number} 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 Average;

👉 실행 결과

출력은 잘 되지만 숫자를 등록할때 뿐만 아니라 input 내에서 숫자를 변경할 때도 getAverage()가 호출되는 문제점이 있다. -> 렌더링할 때마다 계산

이제 useMemo를 이용해 최적화를 해보자.
최적화는 렌더링하는 과정에서 특정 값이 바뀌었을 때만 연산을 실행하고, 원하는 값이 바뀌지 않았다면 이전에 연산했던 결과를 다시 사용하는 방식이다.

const getAverage =numbers =>{...
}

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

    const onChange =(e)=>{...}
    const onInsert = (e)=>{...}
	//추가된 부분
    const avg = useMemo(()=> getAverage(list), [list]);
    return(
        <div>
            <input value ={number} onChange ={onChange}/>
            <button onClick={onInsert}> 등록 </button>
            <ul>
                {list.map((value, index) => 
                    <li key={index}>{value}</li>
                )}
            </ul>
            <div>
              //변경된 부분
                <b>평균 값 : </b>{avg}
            </div>
        </div>
    )
}

🧸✨ 이 포스팅은 '리액트를 다루는 기술' 책을 기반으로 공부한 내용을 정리한 내용입니다.

0개의 댓글