리액트로 프로젝트를 생성하여 개발하는 과정 중 리액트의 필수 문법 및 기초적인 부분, 심화 과정 등을 정리한 문서입니다. 정리한 부분에는 제가 이해하는 관점에서만 정리를 하였기 때문에 초점은 보여주는 형식이 아닌 제가 필요할 때 사용하려는 목적이 담겨져 있습니다. 13번째 노트 정리 페이지에서 예제로 테스트 한 사용자 페이지는 useState로 구성되어 있었습니다. 그 예제를 useReducer 로 변경하였습니다. 아래 코드는 13번째 노트 정리 한 코드 예제입니다. 천천히 따라와 주시기 바랍니다.
현재 정리부터는 소스코드를 제공할 예정입니다. 제공하는 소스코드를 이용하여 따라하실 수 있고 개념을 확실히 잡을 꺼 같아서 올리게 되었습니다. 소스코드 자료는 아래 링크를 참고해주세요.
https://github.com/libtv/React_Note/tree/master/15.%20useReducer_Exam
그러면 useReducer 적용 에 대해 배워보도록 합시다.
# Contents
- useReducer 적용하기
# useReducer 적용하기
천천히 따라오시면서 시작해주시기 바랍니다. 13번째 노트 정리 한 코드는 useState로 정의되어 있었습니다.
해당 적용방법을 이용하여 useState를 useReducer로 변경하고 변경하는 부분 부분을 큰 틀에 맞춰서 열거하였습니다.
그러면 시작하도록 하겠습니다.
내부의 로직을 제거하고 초기 함수와 변수를 정의해주겠습니다.
import "./App.css";
import react, { useCallback, useReducer, useRef } from "react";
import UserList from "./UserList.js";
import CreateUser from "./CreateUser";
function App() {
function reducer(state, action) {
return state;
}
const initialState = {
input: { name: "", email: "" },
users: [
{ id: 0, name: "John", email: "john@gmail.com", active: true },
{ id: 1, name: "Smith", email: "smith@gmail.com", active: false },
{ id: 2, name: "Park", email: "park@gmail.com", active: false },
{ id: 3, name: "Kim", email: "kim@gmail.com", active: false },
],
}
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<CreateUser />
<UserList />
<div>활성화된 사용자 수 : 0</div>
</div>
);
}
export default App;
각각의 변수를 할당하겠습니다.
import "./App.css";
import react, { useCallback, useReducer, useRef } from "react";
import UserList from "./UserList.js";
import CreateUser from "./CreateUser";
function App() {
function reducer(state, action) {
return state;
}
const initialState = {
input: { name: "", email: "" },
users: [
{ id: 0, name: "John", email: "john@gmail.com", active: true },
{ id: 1, name: "Smith", email: "smith@gmail.com", active: false },
{ id: 2, name: "Park", email: "park@gmail.com", active: false },
{ id: 3, name: "Kim", email: "kim@gmail.com", active: false },
],
};
const [state, dispatch] = useReducer(reducer, initialState);
const [inputs, users] = state;
const [name, email] = inputs;
return (
<div>
<CreateUser />
<UserList />
<div>활성화된 사용자 수 : 0</div>
</div>
);
}
export default App;
createUser 컴포넌트를 호출하는 태그 안에 name과 email을 넣고, onChange 함수를 useCallback 함수로 구현하도록 하겠습니다.
import "./App.css";
import react, { useCallback, useReducer, useRef } from "react";
import UserList from "./UserList.js";
import CreateUser from "./CreateUser";
function App() {
function reducer(state, action) {
switch (action.type) {
case "CHANGE_INPUT":
return {
...state,
inputs: {
[action.name]: action.value,
},
};
default:
break;
}
return state;
}
const initialState = {
inputs: { name: "", email: "" },
users: [
{ id: 0, name: "John", email: "john@gmail.com", active: true },
{ id: 1, name: "Smith", email: "smith@gmail.com", active: false },
{ id: 2, name: "Park", email: "park@gmail.com", active: false },
{ id: 3, name: "Kim", email: "kim@gmail.com", active: false },
],
};
const [state, dispatch] = useReducer(reducer, initialState);
const { inputs, users } = state;
const { name, email } = inputs;
const onChange = useCallback(
(e) => {
var { name, value } = e.target;
dispatch({
type: "CHANGE_INPUT",
[name]: value,
});
},
[name, email]
);
return (
<div>
<CreateUser name={name} email={email} onChange={onChange} />
<UserList users={users} />
<div>활성화된 사용자 수 : 0</div>
</div>
);
}
export default App;
reducer 함수에서 해당 액션이 오게 되면 state 값을 변경하도록 구현하였고, onChange() 메소드는 dispatch로 reducer를 호출하는 메소드를 작업하였습니다. 그리고 useCallback 을 사용하여 name과 email 필드가 변경될 때 마다 리랜더링이 호출될 수 있게 작업하였습니다.
onClick메소드를 구현한 코드는 다음과 같습니다.
import "./App.css";
import react, { useCallback, useReducer, useRef } from "react";
import UserList from "./UserList.js";
import CreateUser from "./CreateUser";
function App() {
const nextIndex = useRef(4);
function reducer(state, action) {
switch (action.type) {
case "CHANGE_INPUT":
return {
...state,
inputs: {
[action.name]: action.value,
},
};
case "CREATE_USER":
return {
inputs: initialState.inputs,
users: state.users.concat(action.user),
};
default:
break;
}
return state;
}
const initialState = {
inputs: { name: "", email: "" },
users: [
{ id: 0, name: "John", email: "john@gmail.com", active: true },
{ id: 1, name: "Smith", email: "smith@gmail.com", active: false },
{ id: 2, name: "Park", email: "park@gmail.com", active: false },
{ id: 3, name: "Kim", email: "kim@gmail.com", active: false },
],
};
const [state, dispatch] = useReducer(reducer, initialState);
const { inputs, users } = state;
const { name, email } = inputs;
const onChange = useCallback(
(e) => {
var { name, value } = e.target;
dispatch({
type: "CHANGE_INPUT",
[name]: value,
});
},
[name, email]
);
const onClick = useCallback(() => {
dispatch({
type: "CREATE_USER",
user: {
id: nextIndex.current++,
name,
email,
active: false,
},
});
}, [users]);
return (
<div>
<CreateUser name={name} email={email} onChange={onChange} onClick={onClick} />
<UserList users={users} />
<div>활성화된 사용자 수 : 0</div>
</div>
);
}
export default App;
onToggle, onDelete메소드를 구현한 코드는 다음과 같습니다.
import "./App.css";
import react, { useCallback, useReducer, useRef } from "react";
import UserList from "./UserList.js";
import CreateUser from "./CreateUser";
function App() {
const nextIndex = useRef(4);
function reducer(state, action) {
switch (action.type) {
case "CHANGE_INPUT":
return {
...state,
inputs: {
[action.name]: action.value,
},
};
case "CREATE_USER":
return {
inputs: initialState.inputs,
users: state.users.concat(action.user),
};
case "TOGGLE_USER":
return {
inputs: state.inputs,
users: state.users.map((user) => {
return user.id === action.userId ? { ...user, active: true } : user;
}),
};
case "DELETE_USER":
return {
inputs: state.inputs,
users: state.users.filter((user) => {
return user.id !== action.userId;
}),
};
default:
break;
}
return state;
}
const initialState = {
inputs: { name: "", email: "" },
users: [
{ id: 0, name: "John", email: "john@gmail.com", active: true },
{ id: 1, name: "Smith", email: "smith@gmail.com", active: false },
{ id: 2, name: "Park", email: "park@gmail.com", active: false },
{ id: 3, name: "Kim", email: "kim@gmail.com", active: false },
],
};
const [state, dispatch] = useReducer(reducer, initialState);
const { inputs, users } = state;
const { name, email } = inputs;
const onChange = useCallback(
(e) => {
var { name, value } = e.target;
dispatch({
type: "CHANGE_INPUT",
[name]: value,
});
},
[name, email]
);
const onClick = useCallback(() => {
dispatch({
type: "CREATE_USER",
user: {
id: nextIndex.current++,
name,
email,
active: false,
},
});
}, [users]);
const onToggle = useCallback(
(userId) => {
dispatch({
type: "TOGGLE_USER",
userId,
});
},
[users]
);
const onDelete = useCallback(
(userId) => {
dispatch({
type: "DELETE_USER",
userId,
});
},
[users]
);
return (
<div>
<CreateUser name={name} email={email} onChange={onChange} onClick={onClick} />
<UserList users={users} onToggle={onToggle} onDelete={onDelete} />
<div>활성화된 사용자 수 : 0</div>
</div>
);
}
export default App;
# useReducer vs useState
자 이제 궁금해지는 점이 한가지 있을 것입니다. 어떨 때 useReducer 를 쓰고 어떨 때 useState 를 써야 할까요? 일단, 여기에 있어서는 정해진 답은 없습니다. 상황에 따라 불편할때도 있고 편할 때도 있습니다.
예를 들어서 컴포넌트에서 관리하는 값이 딱 하나고, 그 값이 단순한 숫자, 문자열 또는 boolean 값이라면 확실히 useState 로 관리하는게 편할 것입니다.
const [value, setValue] = useState(true);
하지만, 만약에 컴포넌트에서 관리하는 값이 여러개가 되어서 상태의 구조가 복잡해진다면 useReducer로 관리하는 것이 편해질 수도 있습니다. 이에 대한 결정은, 앞으로 여러분들이 useState, useReducer 를 자주 사용해보시고 맘에드는 방식을 선택하세요.
출처 : https://react.vlpt.us/basic/20-useReducer.html
'오픈소스 > 노드' 카테고리의 다른 글
[Node] React 정리(17) - Context API 를 사용한 전역 값 관리 (0) | 2021.10.19 |
---|---|
[Node] React 정리(16) - 커스텀 Hooks 만들기 (0) | 2021.10.19 |
[Node] React 정리(14) - useReducer를 사용하여 상태 업데이트 분리 (0) | 2021.10.19 |
[Node] React 정리(13) - React.memo을 사용하여 컴포넌트 리렌더링 방지 (0) | 2021.10.19 |
[Node] React 정리(12) - useCallback을 사용하여 성능 최적화 하기 (0) | 2021.10.18 |