Redux를 사용해보자

goodjam92·2023년 4월 11일
0

redux

목록 보기
2/3
post-thumbnail

서론

이 전 글에서 Redux에 대해 전반적으로 알아보았으니 이번 글에서는 한 번 직접 코드를 작성해보면서 알아보겠습니다.

이 글의 코드는 노마드코더의 Redux 강의를 보고 학습하며 정리하였습니다.

리덕스를 활용한 ToDo 구현

React환경에서 ToDo 기능을 만들면서 리덕스를 어떤식으로 활용할 수 있는지에 대해 코드로 배워보도록 하겠습니다. 간편하게 CRA를 활용하여 리액트 프로젝트를 시작하고, Redux를 설치합니다.

  • CRA
yarn create react-app react-redux-learning
//or
npx create-react-app react-redux-learning
  • Redux 설치
yarn add redux react-redux
//or
npm install redux react-redux

만약 react-redux 먼저 설치 후 redux를 설치하게 되면 간혹 문제가 생겼다는 글이 있어서 최대한 redux -> ract-redux 순서로 진행해주세요.

설치가 모두 완료되었으면 코드를 작성해보도록 하겠습니다.

store.js

import { legacy_createStore as createStore } from "redux";
import { addToDo, deleteToDo } from "./action";

const toDoReducer = (state = [], action) => {
  switch (action.type) {
    case addToDo.type:
      return [{text: action.text, id: Date.now()}, ...state];
    case deleteToDo.type:
      return state.filter(toDo => toDo.id !== action.id);
    default: 
      return state;
  }
};

const store = createStore(toDoReducer);
export default store;

리덕스 내부의 상태를 업데이트 할 때 절대 state를 직접적으로 변경하려하면 안됩니다. 위의 코드처럼 배열의 경우엔 새로운 배열로 반환하여 교체해야 합니다. state.push(...) 이런식으로 mutate는 불가합니다.
하지만.. @reduxjs/toolkit을 사용하면 이러한 문법을 허용해준다고 하는데요. 이는 다음 글에서 따로 다루도록 하겠습니다! 일단 직접 상태를 변경하면 안된다라고 알아두시면 좋을 것 같습니다!

action.js

export const addToDo = (text) => {
  return {
    type: "ADD",
    text,
  };
};

export const deleteToDo = (id) => {
  return {
    type: "DELETE",
    id,
  };
};

이렇게 reducer, store, action을 작성하였으면 이제 리액트에서 리덕스를 사용할 수 있도록 index.js에서 Provider로 감싸줍니다.

index.js

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./components/App";
import { Provider } from "react-redux";
import store from "./store";

const root = ReactDOM.createRoot(document.getElementById("root"));

root.render(
  <Provider store={store}>
    <App />
  </Provider>
);

이제 컴포넌트에서 리덕스의 상태 값을 업데이트하거나, 읽어올 수 있습니다. 그럼 이제 ToDo 리스트가 나오는 메인 화면을 작성해보겠습니다.

Home.js

import { useState } from "react";

function Home() {
  const [text, setText] = useState("");

  function onChange(e) {
    setText(e.target.value);
  }

  function onSubmit(e) {
    e.preventDefault();
    setText("");
  }

  return (
    <>
      <h1>To Do</h1>
      <form onSubmit={onSubmit}>
        <input
          type="text"
          placeholder="What To Do?"
          value={text}
          onChange={onChange}
        />
        <button>Add</button>
      </form>
      <ul></ul>
    </>
  );
}

export default Home;

Home 화면은 기본적으로 이렇게 코드를 작성하였습니다. 이제 리덕스를 이용하여 ToDo 내용을 저장하고, <ul>태그 안에 <ToDo /> 컴포넌트를 렌더링 할 수 있도록 코드를 추가하겠습니다. 그럼 추가로 아래 코드를 작성해주세요.
(위 내용에서 지우는 내용 없이 아래에 위치에 맞게 코드를 그냥 추가로작성만 해주세요!)

import { useSelector, useDispatch } from "react-redux";
// ToDo 컴포넌트 파일을 생성해주세요!
import { ToDo } from "./ToDo";
import { addToDo } from "./store"

function Home() {
  ...
  // 리덕스 상태를 구독하는 Hook
  const toDos = useSelector((state) => state);
  // 액션을 발생시키기 위한 dispatch를 사용할 수 있게 해주는 Hook
  const dispatch = useDispatch();
  
  ...
  
  function onSubmit(e) {
    e.preventDefault();
    dispatch(addToDo(text));
    setText("");
  }
  
  return (
    <>
      ...
      </form>
      <ul>
        {toDos.map((toDo) => (
  	      <ToDo {...toDo} key={toDo.id} />
        ))}
      </ul> 
    </>
  )
}

리덕스의 상태 값을 조회하기 위해 useSelector Hook을 사용하였습니다. 그리고 액션을 발생시키기 위해 useDispatch Hook을 사용하여 submit 이벤트가 발생하면 dispatch(action) 함수를 호출하여 현재 text 값을 리덕스 상태 값에 업데이트 합니다.

이제 <ToDo /> 컴포넌트를 작성하면서 ToDo 항목을 제거하는 기능도 추가해보겠습니다.

ToDo.js

import { useDispatch } from "react-redux";
import { deleteToDo } from "../redux/action";

function ToDo({ text, id }) {
  const dispatch = useDispatch();
  
  return (
    <li>
	  {text}
      <button onClick={() => dispatch(deleteToDo(id))}>Delete</button>
    </li>
  );
}

export default ToDo;

생각보다 간단하지 않나요? Delete 버튼을 누르면 dispatch(deleteToDo(id)) 함수가 호출되어 store 내부의 리듀서에서 action.type에 해당하는 로직으로 상태 값을 새로 생성합니다. 만약에 Delete 버튼을 눌러도 삭제가 안되신다면 리듀서에서 toDo.idaction.id의 데이터 타입이 동일한지 확인해보시길 바랍니다.

정리

코드를 모두 작성 후 toDo 추가와 삭제 모두 잘 작동하시나요? 막상 직접 코드를 작성하면서 사용해보니 제가 생각했던 것보다 기본적인 사용법은 어렵진 않았습니다. 😀
이 다음 글에서는 지금 작성한 코드들을 @reduxjs/toolkit을 사용하여 조금 더 다듬어보도록 하겠습니다. 그럼 다음 글에서 뵙겠습니다

profile
습관을 들이도록 노력하자!

0개의 댓글