React - useReducer, 커스텀 hook

김해김씨가오리·2022년 12월 6일
0

REACT

목록 보기
9/14

useReducer

useState의 대체 함수.
(state, action) => newState의 형태.
reducer를 받고 dispatch의 메서드와 짝의 형태로 현재 state를 반환.

const [state, dispatch] = useReducer(reducer, initialArg, init);
state //현재상태
dispatch //action으로 보내는 함수
reducer //연결되는 함수명
initialArg //초기값

useReducer사용하여 active 사용자 count하기

counter.jsx
import React, {useReducer} from 'react'

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

    const [number, dispatch] = useReducer(reducer, 0);
    
    
    const increase = () => {
        dispatch({type : "INCREMENT"})
    }
    
    const decrease = () => {
        dispatch({type : "DECREMENT"})
    }
  return (
    <div>
        <h1>{number}</h1>
        <button onClick={increase}>+1</button>
        <button onClick={decrease}>-1</button>
    </div>
  )
}

export default Counter
action// dispatch에서 보낸 객체를 parameter로 받아옴

custom hook

반복되는 로직을 쉽게 재사용 하기 위해 직접 만들어 사용하는 hook
보통 파일 이름은 Use-로 시작

user를 새로 input하는 custom hook을 만들어 보자

UseInputs.js
import {useState, useCallback} from 'react'

const UseInputs = (initialForm) => {
    const [form, setForm] = useState(initialForm);
    
    const onChange = useCallback((e)=> {
        const {name, value} = e.target;
        setForm(form => ({...form, [name]:value}))
    }, [])
    
    const reset = useCallback(()=>setForm(initialForm), [initialForm]);
    //form을 초기화
  return (
    [form, onChange, reset]
  )
}

export default UseInputs
setForm(form => ({...form, [name]:value})) // 객체 리터럴 표현을 반환하기 위해 함수 본문을 괄호속에 넣음.
App.js
import React, { useReducer, useCallback, useRef, useMemo }  from 'react'
import UserList from './components/UserList'
import CreateUser from './components/CreateUser'
import UseInputs from './components/UseInputs'

const initialState = {
  users : [
    {
      id : 1,
      username : 'jisung',
      email : 'jisung@gmail.com',
      Active : true
    },
    {
      id : 2,
      username : 'mark',
      email : 'marklee@naver.com',
      Active : false

    },
    {
      id : 3,
      username : 'jeongwoo',
      email : 'jeongwoo@gmail.com',
      Active : false
    }
  ]
}

function reducer(state, action){
  switch(action.type){
    case "CREATE_USER":
      return{
        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:
          throw new Error("액션 없음!");
  }
}

function countActiveUsers(users){
  return users.filter(user => user.active).length;
}
function App() {
  const [state, dispatch] = useReducer(reducer, initialState);
  const {users} = state;
  const nextId = useRef(4);
  
  const [form, onChange, reset] = UseInputs({
    username : "",
    email : ""
  });

  const {username, email} = form;

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

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

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

  const count = useMemo(()=>countActiveUsers(users), [users])

  return (
    <>
      <CreateUser 
        username={username} 
        email={email} 
        onChange={onChange} 
        onCreate={onCreate} 
      /><br/>
      <UserList users={users} onToggle={onToggle} onRemove={onRemove}/><br />
      <div>Active 상태의 사용자 수 : {count} </div>
    </>
  );
}

export default App;

출처 :
useReducer
커스텀 hooks 만들기

profile
그냥 기록용!!!

0개의 댓글