본문 바로가기

오픈소스/노드

[Node] React 정리(15) - useReducer를 사용한 코드 예제

 

리액트로 프로젝트를 생성하여 개발하는 과정 중 리액트의 필수 문법 및 기초적인 부분, 심화 과정 등을 정리한 문서입니다. 정리한 부분에는 제가 이해하는 관점에서만 정리를 하였기 때문에 초점은 보여주는 형식이 아닌 제가 필요할 때 사용하려는 목적이 담겨져 있습니다. 13번째 노트 정리 페이지에서 예제로 테스트 한 사용자 페이지는 useState로 구성되어 있었습니다. 그 예제를 useReducer 로 변경하였습니다. 아래 코드는 13번째 노트 정리 한 코드 예제입니다. 천천히 따라와 주시기 바랍니다.

 

 현재 정리부터는 소스코드를 제공할 예정입니다. 제공하는 소스코드를 이용하여 따라하실 수 있고 개념을 확실히 잡을 꺼 같아서 올리게 되었습니다. 소스코드 자료는 아래 링크를 참고해주세요.

https://github.com/libtv/React_Note/tree/master/15.%20useReducer_Exam

 

GitHub - libtv/React_Note: This is a notebook organized by React.

This is a notebook organized by React. Contribute to libtv/React_Note development by creating an account on GitHub.

github.com

 

러면 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

 

20. useReducer 를 사용하여 상태 업데이트 로직 분리하기 · GitBook

20. useReducer 를 사용하여 상태 업데이트 로직 분리하기 이 프로젝트에서 사용된 코드는 다음 링크에서 확인 할 수 있습니다. useReducer 이해하기 우리가 이전에 만든 사용자 리스트 기능에서의 주

react.vlpt.us