리액트 - App 에서 useReducer 사용하기

정영찬·2022년 2월 23일
0

리액트

목록 보기
21/79

useReducer

이제 useReducer가 어떻게 돌아가는지 알았으니 App.js에다가 적용을 시켜보자.

첫번째로 해야할 일은 App 컴퍼넌트에서 사용할 초기 상태를 컴퍼넌트 바깥에 선언하는 것이다.

inputs의 초기값과 users의 초기값을 선언해주면된다.

const initialState ={
  inputs: {
    username: '',
    email: '',
  },
  users:[
    {
        id: 1,
        username: 'carrot',
        email: 'carrot@gamil.com',
        active: true,
    },
    {
        id: 2,
        username: 'apple',
        email: 'apple@gamil.com',
        active: true,
    },
    {
        id: 3,
        username: 'tomato',
        email: 'tomato@gamil.com',
        active: false,
    }
]
}

그다음 App 컴퍼넌트 내부에서 선언한 내용을 전부 제거한다.

function App() {

  const style = {
   margin : '20px'
  }
  
  return (
    <div style={style}>
     <CreateUser/>
     <UserList users = {[]} />
     <div>활성 사용자 수: 0</div>
    </div>
  );

}

reducer를 작성한다.

function reducer(state,action){
  return state;
}

App.js내부에 useReducer를 작성하고 객체의 비구조화 할당으로 데이터를 쉽게 사용할 수 있게 변경해준다.

const [state, dispatch] = useReducer(reducer, initialState)
  const {users} = state;
  const {username, email} = state.inputs;

onChange

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

reducer를 switch문으로 나누어서 action.type마다 다른 작업을 수행하게 작성한다. onChange의 경우는 불변성 유지를 위해서 배열을 새로 만들고 기존에 있던 값을 집어 넣은뒤에 값을 수정하면 된다.

function reducer(state,action){
  switch(action.type){
    case 'CHANGE_INPUT':
      return{
        ...state,
        inputs:{
          ...state.inputs,
          [action.name] : action.value
        }
      };
      default:
        throw new Error('Unhandled adction');
  }
}

onCreate

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

id값은 nexId.current값을 username,email 값은 사용자가 입력한 값을 받아온다.

case 'CREATE_USER':
      return{
        inputs: initialState.inputs,
        users: state.users.concat(action.user)
      }

action.type 가 'CREATE_USER'인 경우에
inputs 를 초기의 inputs값으로 변경하고, users 배열은 초기 배열의 값에다가 action으로 가져온 user 항목을 추가한 값으로 변경된다.

usestate로 사용한 경우에는 input 초기화와 배열항목 추가를 따로 했었지만, reducer의 경우에는 이 두가지를 동시에 선언이 가능하다.

onToggle, onRemove

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


  const onRemove = useCallback( id => {
    dispatch({
      type:'REMOVE_USER',
      id
    });
  }, []);
 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('Unhandled adction');
  }

countActiveusers

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

이전에 만든 함수를 사용해서 작성한다.

profile
개발자 꿈나무

0개의 댓글