본문 바로가기

Web Tech/react

react 기본 - 16.useReducer

useReducer
사용자 리스트 기능에서의 주요 상태 업데이트 및 컴포넌트의 상태 업데이트 로직을 컴포넌트에서 분리시킬 수 있습니다.
컴포넌트에서 관리하는 값이 여러개가 되어 상태의 구조가 복잡하다면 useReducer 사용, 컴포넌트에서 관리하는 값이 하나고 단순한 숫자 또는 문자열이라면 useSate로 관리

reducer 기본 문법
reducer 에서 반환하는 상태는 곧 컴포넌트가 지닐 새로운 상태가 되며, action은 업데이트를 위한 정보를 가지고 있습니다.
type 값을 지닌 객체 형태로 사용하지만, 꼭 따라야 할 규칙은 없음

// 현재 상태와 액션 객체를 파라미터로 받아서 새로운 상태를 반환해주는 함수
function reducer(state, action) {
  // 새로운 상태를 만드는 로직
  // const nextState = ...
  return nextState;
}

 

useReducer 기본 문법

//state는 우리가 앞으로 컴포넌트에서 사용할 수 있는 상태를 가르킴
//dispatch 는 액션을 발생시키는 함수

//reducer === reducer의 이름의 함수
//dispatch === 초기 상태
const [state, dispatch] = useReducer(reducer, initialSatate);

Counter.js

import React, {useReducer} from 'react';

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

function Counter() {
    const [number, dispatch] = useReducer(reducer,0);

    const onIncrease = () => {
        dispatch({type : 'INCREMENT'});
    }
    const onDecrease = () => {
        dispatch({type: 'DECREMENT'});
    }
    return(
        <React.Fragment>
            <h1>{number}</h1>
            <button onClick={onIncrease} type="button">+1</button>
            <button onClick={onDecrease} type="button">-1</button>
        </React.Fragment>
    )
}
export default Counter;

App.js

import React, {useRef, useReducer, useMemo, useCallback} from 'react';
import Inner from "./Inner";
import UserList from "./UserList";
import CreateUser from "./CreateUser";

function countActiveUsers(users) {
    console.log('활성 사용자 수를 세는중')
    return users.filter(user => user.active).length;
}

const initialState = {
    inputs: {
        username: '',
        email: ''
    },
    users: [
        {
            id: 1,
            username: 'a',
            email: 'a@aaa.com',
            active: true
        },
        {
            id: 2,
            username: 'b',
            email: 'b@bbb.com',
            active: false
        },
        {
            id: 3,
            username: 'c',
            email: 'c@ccc.com',
            active: false
        }
    ]
};

function reducer(state, action) {
    switch (action.type) {
        case 'CHANGE_INPUT' :
            return {
                ...state,
                inputs: {
                    ...state.inputs,
                    [action.name] : action.value
                }
            };
        case 'CREATE_USER':
            return {
                inputs: initialState.inputs,
                users: state.users.concat(action.user)
            };
        case 'TOGGLE_USER':
            return {
                ...state,
                users: state.users.map(user =>
                    user.id === action.id ? {...user, active : !user.active} : user
                )
            };
        case 'REMOVE_USER' :
            return {
                ...state,
                users: state.users.filter(user => user.id !== action.id)
            };
        default:
            return state;
    }
}

function App() {
    const [state, dispatch] = useReducer(reducer, initialState);
    const nextId = useRef(4);

    const {users} = state;
    const {username, email} = state.inputs;

    const onChange = useCallback(e => {
        const { name, value } = e.target;
        dispatch({
            type: 'CHANGE_INPUT',
            name,
            value
        });
    }, []);

    const onCreate = useCallback(() => {
        dispatch({
            type: 'CREATE_USER',
            user: {
                id: nextId.current,
                username,
                email
            }
        });
        nextId.current += 1;
    }, [username, email]);

    const onToggle = useCallback(id=> {
        dispatch({
            type : 'TOGGLE_USER',
            id
        });
    }, []);

    const onRemove = useCallback(id=> {
       dispatch({
           type: 'REMOVE_USER',
           id
       }) ;
    }, []);

    const count = useMemo(() => countActiveUsers(users), [users]);
    return (
        <React.Fragment>
            <Inner>
                <CreateUser username={username} email={email} onChange={onChange} onCreate={onCreate}/>
                <UserList users={users} onToggle={onToggle} onRemove={onRemove}/>
                <p>활성사용자 수 : {count}</p>
            </Inner>
        </React.Fragment>
    );
}

export default App;

'Web Tech > react' 카테고리의 다른 글

react 기본 - 18.Context API 로 전역 값 관리  (0) 2021.12.06
react 기본 - 17.커스텀 Hooks  (0) 2021.12.06
react 기본 - 15.React.memo  (0) 2021.11.30
react 기본 - 14.useCallback  (0) 2021.11.30
react 기본 - 13.useMemo  (0) 2021.11.23