useReducer 사용하기

LNSol·2022년 10월 24일

React

목록 보기
4/10

핵심 키워드


액션

상태에 어떤 변화가 필요하다면 액션(actions)이라는 것이 발생한다. 액션 객체는 다음과 같은 형식으로 이루어져 있다. 액션 객체는 반드시 type 필드를 가지고 있어야 하고 이를 액션의 이름이라고 생각하면 된다. 그 이외의 값들은 상태 업데이트를 할 때 필요한 값이다.

{ 
	type: 'ADD_USER',
	user: {
		id: 1,
		name: '아갈인파이터',
		age: 25
	}
}

액션 생성 함수

액션 생성 함수(action creator)는 액션 객체를 만들어주는 함수이다.

const addUser = (user) => ({
	type: 'ADD_USER',
	user,
});

리듀서

리듀서(reducer)는 새로운 상태를 반환하여 상태를 업데이트(상태 변화)를 일으키는 함수이다. 액션을 만들어 발생시키면 리듀서가 현재 상태와 전달받은 액션 객체를 파라미터로 받아온다. 그리고 새로운 상태를 만들어 반환한다. 이때 상태는 불변성을 유지해야한다!

const initialState = {
	count: 1
};

const reducer =(state = initialState, action) => {
	switch(action.type) {
		case 'INCREMENT':
			return { count: state.count + 1 };
		case 'DECREMENT':
			return { count: state.count - 1 };
		default:
			return state;
		}
};

디스패치

디스패치(dispatch)는 액션을 발생시키는 것이다. 이 함수는 dispatch(action) 과 같은 형태로 액션 객체를 파라미터로 넣어서 호출한다. 디스패치로 액션을 발생시키면 리듀서가 액션에 따라 새로운 상태를 반환한다.(상태 업데이트)

dispatch({ type: 'INCREMENT' });


useReducer 사용해보기


Counter 만들어보기

import { useReducer } from 'react';

const reducer = (state, action) => {
	switch(action.type) {
		case 'INCREMENT':
			return { count: state.count + 1 };
		case 'DECREMENT':
			return { count: state.count - 1 };
		default:
			return state;
	}
};

const Counter = () => {
	const [state, dispatch] = useReducer({ count: 0 });

	return (
		<>
			<h1>Count: {state.count}</h1>
			<button onClick={() => dispatch({ type: 'INCREMENT' })}>+1</button>
			<button onClick={() => dispatch({ type: 'DECREMENT' })}>-1</button>
		</>
	);
};
export default Counter;


UserList 만들어보기

다음 예제 코드에는 좋지 않은 코드가 있다. 여기서는 useReducer의 사용법만 간단하게 알아보자.

import { useRef, useReducer } from 'react';

const reducer = (state, action) => {
	switch(action.type) {
		case 'ADD_USER':
			return state.concat(action.user);
		case 'REMOVE_USER':
			return state.filter((user) => user.name !== action.userName);
		default:
			return state;
	}
};

const UserList = () => {
	const [state, dispatch] = useReducer(reducer, []);
	const userNameRef = useRef(null);
	const userAgeRef = useRef(null);

	const onAddUser = () => {
		const user = {
			name: userNameRef.current.value,
			age: parseInt(userAgeRef.current.value)
		}
		dispatch({ type: 'ADD_USER', user });
	};
	const onRemoveUser = (userName) => {
		dispatch({ type: 'REMOVE_USER', userName });
	};

	return(
		<>
			이름: <input type='text' ref={userNameRef} />
			나이: <input type='number' ref={userAgeRef} />
			<button onClick={onAddUser}>추가</button>
			<ul>
				{state.map(({ name, age }, i) => (
					<li key={i}>
						{name}({age})
						<button onClick={() => onRemoveUser(name)}>삭제</button>
					</li>
				))}
			</ul>
		</>
	);
};
export default UserList;

😨 useReducer의 사용법을 간단히 알아보기 위해 위와 같은 코드를 작성했지만, 좋지 못한 코드의다. 첫 번째로, onRemoveUser에서 삭제할 유저의 조건을 이름으로 지정했다. 중복된 이름이 있다면 모두 삭제될 것이다. 이럴때는 user 객체에 id를 추가하는 것이 좋다.


그리고 두 번째로, 반복되는 li의 key를 배열의 인덱스로 주고있다. 유저가 추가되고 삭제됨에 따라 인덱스는 변한다. 이 역시 user에 id를 추가하고 key를 id로 주는 것이 바람직하다!!😨

0개의 댓글