ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • React - App 컴포넌트에서 useReducer사용
    React 2020. 9. 11. 15:20

     

     

    React - useReducer

    이전에는 useState로 상태 업데이트 해줬음 useReducer로도 할 수 있음 useState는 setValue(5); 와 설정하고 싶은 다음 상태를 직접 지정해줘서 업데이트함 useReducer는 action이라는 객체를 기반으로 상태를 �

    startersdev.tistory.com

     

    1. App 컴포넌트에서 사용할 초기 상태를 컴포넌트 밖에 선언해 줌

    const initialState = {
      inputs: {
        username: '',
        email: '',
      },
      users: [
        {
          id: 1,
          username: 'starters',
          email: 'public.starters@gmail.com',
          active: true,
        },
        {
          id: 2,
          username: 'tester',
          email: 'tester@gmail.com',
          active: false,
        },
        {
          id: 3,
          username: 'jajajojo',
          email: 'jajajojo@gmail.com',
          active: false,
        }
      ]
    }

     

    2. App컴포넌트에서 사용한 모든 로직 지우기, 내부 props도 지우기

    function App() {
    
      return (
        <>
          <CreateUser
          />
          <UserList users={[]}/>
          <div>활성 사용자 수: 0</div>
        </>
      );
    }

    - users에 임시로 빈 배열 넣고, count는 0으로

     

    3. useState 대신에 useReducer 불러오기

    import React, { useRef, useReducer, useMemo, useCallback } from 'react';

     

    4. reducer 틀 잡기

    function reducer(state, action){
      return state;
    }
    
    function App() {
      const [state, dispatch] = useReducer(reducer, initialState);
      return (
        <>
          <CreateUser
          />
          <UserList users={[]}/>
          <div>활성 사용자 수: 0</div>
        </>
      );
    }

     

     

    5. state 안에 있는 users와 inputs 비구조 할당으로 추출 후, 컴포넌트를 통해 props로 전달

    function App() {
      const [state, dispatch] = useReducer(reducer, initialState);
      const { users } = state;
      const { username, email } = state.inputs;
      return (
        <>
          <CreateUser
            username={username}
            email={email}
          />
          <UserList users={users}/>
          <div>활성 사용자 수: 0</div>
        </>
      );
    }

     

    6. onChange함수 구현하고 사용

    const onChange = useCallback(e => {
        const { name, value } = e.target;
        dispatch({
          type: 'CHANGE_INPUT',
          name,
          value
        });
      }, []);
    
      return (
        <>
          <CreateUser
            username={username}
            email={email}
            onChange={onChange}
          />
          ...

     

     

     

    7. onCreate()

    const onCreate = useCallback(() => {
          dispatch({
            type: 'CREATE_USER',
            user: {
              id: 1,
              username,
              email,
            }
          });
        }, [username, email]);
    
        return (
          <>
            <CreateUser

    - id 는 임의로 1, 나중에 useRef로 관리해주어야 함

     

    1) nextId 값 관리

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

    - App함수 상단에 선언, 초기값은 4 기존에 3개 들어있기 때문

     

    2) create 함수에 넣어줌

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

    3) reducer 함수에도 추가

    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)
          }
        default:
          throw new Error('Unhandled action');
    
      }
    }

    4) props도 지정

    <CreateUser
      username={username}
      email={email}
      onChange={onChange}
      onCreate={onCreate}
    />

    -> 이러고 나면 새 글 생성할 수 있음

     

    8. onToggle / onRemove

    - reducer 안에 먼저 추가

    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)
    };
    

    - 함수 생성, props 추가

    const onToggle = useCallback(id => {
          dispatch({
            type: 'TOGGLE_USER',
            id
          });
        }, []);
    
        const onRemove = useCallback(id => {
          dispatch({
            type: 'REMOVE_USER',
            id
          });
        }, []);
    
        return (
          <>
            <CreateUser
              username={username}
              email={email}
              onChange={onChange}
              onCreate={onCreate}
            />
          <UserList users={users}
            onToggle={onToggle}
            onRemove={onRemove}/>
          <div>활성 사용자 수: 0</div>
        </>
      );

     

    9. 활성 사용자 수

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

    - 이전과 동일, useMemo 사용하고 props 추가

     

     

    ※ 언제 useReducer 사용하고 useState 사용할 지

    - 확실하게 정해진 것은 없음

    - 값이 한두개이거나 boolean값이면 useState가 편할 것

    - 컴포넌트에서 관리하는 값이 여러개이거나 구조가 복잡하면 useReducer가 나을 수 있음

    - setUsers, setInputs 처럼 useState자주 사용되면 useReducer 사용을 고려해보는 것도 좋음

     

     

     

    이전 코드

    import React, { useRef, useState, useMemo, useCallback } from 'react';
    import UserList from './UserList';
    import CreateUser from './CreateUser';
    
    function countActiveUsers(users){
      console.log('활성 사용자 수를 세는 중...');
      return users.filter(user => user.active).length;
    }
    
    function App() {
      const [inputs, setInputs] = useState({
        username: '',
        email: ''
      });
      const {username, email} = inputs;
      const onChange = useCallback(e => {
        const {name, value} = e.target;
        setInputs({
          ...inputs,
          [name]: value
        });
      }, [inputs]);
    
      const [users, setUsers] = useState([
        {
          id: 1,
          username: 'starters',
          email: 'public.starters@gmail.com',
          active: true,
        },
        {
          id: 2,
          username: 'tester',
          email: 'tester@gmail.com',
          active: false,
        },
        {
          id: 3,
          username: 'jajajojo',
          email: 'jajajojo@gmail.com',
          active: false,
        }
      ]);
    
      const nextId = useRef(4);
    
      const onCreate = useCallback(() => {
        const user = {
          id: nextId.current,
          username,
          email,
        };
        setUsers(users => users.concat(user));
        setInputs({
          username: '',
          email: ''
        });
    
        console.log(nextId.current);
    
        nextId.current += 1;
      }, [username, email]);
    
      const onRemove = useCallback(id => {
        setUsers(users => users.filter(user => user.id !== id))
      }, []);
    
      const onToggle = useCallback(id => {
        setUsers(users => users.map(
          user => user.id === id
            ? { ...user, active: !user.active }
            : user
        ));
      }, []);
    
      const count = useMemo(() => countActiveUsers(users), [users]);
    
      return (
        <>
          <CreateUser
            username={username}
            email={email}
            onChange={onChange}
            onCreate={onCreate}
          />
          <UserList users={users} onRemove={onRemove} onToggle={onToggle}/>
          <div>활성 사용자 수: {count}</div>
        </>
      );
    }
    
    export default App;
    

    'React' 카테고리의 다른 글

    React - Context API(전역 값 관리)  (0) 2020.09.13
    React - 커스텀 hook 만들기  (0) 2020.09.13
    React - useReducer  (0) 2020.09.11
    React - 컴포넌트 리렌더링 방지(React.memo)  (0) 2020.09.11
    React - 함수 재사용(useCallback)  (0) 2020.09.11
Designed by Tistory.