본문 바로가기
source-code/React

useReducer

by mattew4483 2023. 8. 15.
728x90
반응형

useReducer

왜?

사실 현재 운영 중인 서비스에서 useReducer를 굳이 사용할 필요를 느끼지 못했다.
앵간한 상태는 useState와 Redux를 통해 관리했고...
결정적으로, reducer의 강점인 이전 값에 의존적인 상태의 업데이트가 필요한 경우가 딱히 없었기 때문!

하지만 최근 리팩토링 및 안정성에도 신경을 쓰면서,
useReducer를 적재적소에 사용해
setter를 직접적으로 노출시키지 않음 + 익명 함수 호출X 등의 이점을 챙겨가고자 한다!

 

reducer

너무 유용하게 사용되는 reduce 메서드!

Array.prototype.reduce()

배열의 각 요소에 대해 주어진 리듀서 (reducer) 함수를 실행하고, 하나의 결과값을 반환한다.

 

useState

앱에서 빈번히 이뤄지는 모달 visible 상태 관리를 생각해보자.

const App = () => {
	const [visible, setModalVisible] = useState(false)
    ...
    
    return (
    	<>
    		<button onClick={() => setModalVisible(!visible)}/>	
        </>
    )
}

와 같은 형태로 작성이 될테다!
물론 이도 문제 없이 동작은 할테지만... 개선할 여지도 충분!

  1. setter 함수 노출
    졸린 오후... 나도 모르는 사이 onclick={() => setModalVisible(false)} 와 같은 실수를 저질렀다면..?
    유저는 모달을 켤 수도, 끌 수도 없는 불상사가 생기고 만다!
    즉 setter 함수에 직접적으로 값을 전달해 업데이트함으로 인해 발생하는 버그 가능성↑ !
  2. 익명 함수
    onClick에 익명 함수를 전달해 실행하는 것 역시 코드 이해를 어렵게 만드는 주범!
    → () => setModalVisible(!visible) 만 봐서는... 해당 버튼이 모달을 끄는지, 켜는지 알 수가 없다

 

useReducer

useReducer를 통해 위의 문제점들을 해결할 수 있다.

const [state, dispatch] = useReducer(reducer, initialArg, init);

기본 사용 형태! 친근한 reduce 메서드가 생각난다.

useReducer를 활용해 모달 제어를 코드를 작성하면...

const App = () => {
	const [visible, toggleModal] = useReducer((pre) => !pre, false)
    ...
    
    return (
    	<>
    		<button onClick={toggleModal}/>	
        </>
    )
}
  1. 이제 개발자는 setter 함수에 특정 값을 직접적으로 전달하지 않는다!
    대신 toggleModal이라는 dispatch를 통해 action을 호출하고, 해당 action은 type과 payload를 통해 정해진 상태 업데이트 로직을 수행할테다!
  2. onClick시 toggleModal이란 함수 실행 → 누가 봐도 해당 버튼은 modal을 toggle해줌을 직관적으로 알 수 있다!

 

reducer, action, dispatch

redux에 익숙하다면 물흐르듯 흘러갈 개념들!
→ 상태 관리를 담당하는 여러 함수를 하나로 관리 + 컴포넌트 외부에 상태 관리 함수(reducer)를 둘 수 있다는 장점 역시 챙겨갈 수 있겠다.

const initialState = {count: 0};

function reducer(state, action) {
	// state, action -> reducer의 표준 형태!	
    // state = 이전 값
	// action = {type : 'type' , payload : value}
    
    switch (action.type) {
      case 'increment':
        return {count: state.count + 1};
      case 'decrement':
        return {count: state.count - 1};
      default:
        throw new Error();
    }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  // useReducer는 reduce 메서드처럼 각 요소에 실행될 함수, 즉 reducer 함수를 전달받는다
  // reduce 메서드와 마찬가지로 초깃값을 지정해줄 수 있다
  
  // reducer(action)을 호출하는 함수 = dispatch
  
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}
728x90
반응형

'source-code > React' 카테고리의 다른 글

React Query - Placeholder, Initial Data  (0) 2023.08.16
React Query - keepPreviousData  (0) 2023.08.15
useTransition hooks  (0) 2023.08.15
patch-package 사용하기  (0) 2021.05.24
CRA에 Next.js 적용하기 3  (0) 2021.05.14