상세 컨텐츠

본문 제목

React_useReducer

React

by 뚠뚠혀나 2021. 11. 12. 14:44

본문

useReducer

useReducer는 useState와 같이 상태관리를 도와주는 Hook이다.

이 Hook 함수를 사용하면 컴포넌트의 상태 업데이트 로직을 컴포넌트에서 분리시킬 수 있다.

상태 업데이트 로직을 컴포넌트 바깥에 작성 할 수도 있고, 다른 파일에 작성 후 불러와서 사용 할 수도 있다.

 

 

 

같은 작업을 useState와 useReducer로 해보았다.

 

useState

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

// active값이 true인 사용자의 수를 세어 화면에 렌더링하기.
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: 'velopert',
        email: 'public.velopert@gmail.com',
        active: true
    },
    {
        id: 2,
        username: 'test1',
        email: 'test1@gmail.com',
        active: true
    },
    {
        id: 3,
        username: 'test3',
        email: 'test3@gmail.com',
        active: false
    },
]);

const nextId = useRef(4);
//useRef로 관리하는 변수는 값이 바뀐다고해서
//컴포넌트가 리렌더링되지 않는다.

const onCreate = useCallback( () => {
  const user = {
    id: nextId.current,
    username,
    email
  };

  // 배열에 새 항목 추가하기

  //1. spread 연산자를 사용하는 방법
  //setUsers([...users,user]); 

  //2. concat 함수를 사용하는 방법
  setUsers(users.concat(user)); 
  

  setInputs({
    username: '',
    email: ''
  });
  nextId.current += 1;
}, [username, email]);


  // 배열에 항목 삭제하기

  //user.id가 파라미터로 일치하지 않는 원소만 추출해서 새로운 배열을 만듦.(filter사용)
  //user.id가 id와 같은 것을 제거.
const onRemove = useCallback(
  id => {
  setUsers(users.filter(user => user.id !==id));
}, []);


  // 배열 항목 수정하기(상태수정)
  // 배열의 불변성을 유지하면서 배열을 업데이트 하기위해 map 함수 사용
  // id 값을 비교하여 id가 다르다면 그대로 두고, 같다면 active 값을 반전 시킴.
const onToggle = useCallback(
 id => {
  setUsers(
    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;

 

useReducer

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

// active값이 true인 사용자의 수를 세어 화면에 렌더링하기.
function countActiveUsers(users) {
  console.log('활성사용자수세는중')
  return users.filter(user=>user.active).length;
}

const initilState = {
  inputs: {
    username: '',
    email: ''
  },
  users: [
    {
              id: 1,
              username: 'velopert',
              email: 'public.velopert@gmail.com',
              active: true
          },
          {
              id: 2,
              username: 'test1',
              email: 'test1@gmail.com',
              active: true
          },
          {
              id: 3,
              username: 'test3',
              email: 'test3@gmail.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: initilState.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,initilState);
  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(
    <>
    <CreateUser username={username} email={email} onChange={onChange} onCreate={onCreate}/>
    <UserList users={users} onToggle={onToggle} onRemove={onRemove}/>
    <div>활성사용자 수 : {count}</div>
    </>
  );
}

export default App;

'React' 카테고리의 다른 글

React_Router에서 props 전달하기  (0) 2021.11.22
React_React Icons  (0) 2021.11.18
React_useMemo  (0) 2021.11.11
React_useEffect  (0) 2021.11.11
React _ 배열 항목 수정하기  (0) 2021.10.03

관련글 더보기

댓글 영역