[React] todolist를 통해 리덕스 복습하기

양선희·2021년 5월 26일

리액트

목록 보기
16/16
post-thumbnail

리덕스 모듈이란?

리덕스 모듈이란 다음 항목들이 모두 들어있는 자바스크립트 파일을 의미

  • 액션 타입
  • 액션 생성함수
  • 리듀서

==> 리듀서와 액션 관련 코드들을 하나의 파일에 몰아서 작성하면 이를 Ducks 패턴이라고 부름.

✍ todos.js

/* 액션 타입 선언 */
const ADD_TODO = "todos/ADD_TODO"; // 할일 항목을 추가
const TOGGLE_TODO = "todos/TOGGLE_TODO"; //할일 항목을 체크

/* 액션 생성함수 선언 */
let nextId = 1; // todo 데이터에서 사용 할 고유 id
export const addTodo = (text) => ({
  type: ADD_TODO,
  todo: {
    //새로운 todo를 여기서 만들어줌
    id: nextId++, // 호출되면 id 값에 1이 더해지도록 함
    text, // 받아온 text파라미터 값을 넣어줌
  },
});

//특정 id를 선택해서 토글하는 작업
export const toggleTodo = (id) => ({
  type: TOGGLE_TODO,
  id,
});

/* 초기 상태 선언 */
// 리듀서의 초기 상태는 꼭 객체타입일 필요 x
const initialState = [
  /*
  {
    id: 1,
    text: "예시",
    done: false,
  },
  */
];

// 리듀서 작성
export default function todos(state = initialState, action) {
  switch (action.type) {
    case ADD_TODO:
      return state.concat(action.todo); // todo라는 객체를 액션에 담아서 가져옴
    case TOGGLE_TODO: //불변성을 지키면서 특정id를 가진 항목을 찾아 done값을 반전시켜야 되므로 map함수 사용
      return state.map(
        (todo) =>
          todo.id === action.id // todo의id 가 액션을 통해 가져온 id와 일치하면
            ? { ...todo, done: !todo.done } // done 값을 반전시키고
            : todo // 아니라면 그대로 둠
      );
    default:
      return state;
  }
}

액션생성함수는 export로 써서 내보내지만
리듀서는 expert default라고 써야함

리액트 프로젝트에 리덕스 적용

$ yarn add react-redux

✍ index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './modules';

const store = createStore(rootReducer); 
// createStore는 스토어를 만들어주는 리덕스 함수로서 리듀서를 파라미터로 넣는다

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

serviceWorker.unregister();

index.js 에서 Provider라는 컴포넌트를 불러와서 App 컴포넌트를 감싸준다. 그리고 Provider의 props 에 store 를 넣어야함

✍ Todos.js

import React, { useState } from "react";

// 컴포넌트 최적화를 위하여 React.memo를 사용합니다
const TodoItem = React.memo(function TodoItem({ todo, onToggle }) {
 return (
   <li
     style={{ textDecoration: todo.done ? "line-through" : "none" }}
     onClick={() => onToggle(todo.id)}
   >
     {todo.text}
   </li>
 );
});

// 컴포넌트 최적화를 위하여 React.memo를 사용합니다
const TodoList = React.memo(function TodoList({ todos, onToggle }) {
 // todos는 여러개의 todo가 들어있는 배열
 // 여러개의 todo에 대하여 todoitem을 렌더링
 return (
   <ul>
     {todos.map((todo) => (
       <TodoItem key={todo.id} todo={todo} onToggle={onToggle} />
     ))}
   </ul>
 );
});

function Todos({ todos, onCreate, onToggle }) {
 // 리덕스를 사용한다고 해서 모든 상태를 리덕스에서 관리해야하는 것은 아닙니다.
 const [text, setText] = useState("");
 const onChange = (e) => setText(e.target.value);
 const onSubmit = (e) => {
   e.preventDefault(); // Submit 이벤트 발생했을 때 새로고침 방지
   onCreate(text);
   setText(""); // 인풋 초기화
 };

 return (
   <div>
     <form onSubmit={onSubmit}>
       <input
         value={text}
         placeholder="할 일을 입력하세요.."
         onChange={onChange}
       />
       <button type="submit">등록</button>
     </form>
     <TodoList todos={todos} onToggle={onToggle} />
   </div>
 );
}

export default Todos;

todos라는 프롭스를 가져와서 배열을 통해 여러개의 할일 항목들을 보여줄것인데
여러개의 할일 항목들을 보여주는 것은 todolist가 담당
oncreate 새로운 데이터를 등록
ontoggle은 todolist에서 todoitem으로 그대로 전달해주고
todoitem에서는 ontoggle함수에서 자신이 받아온 todo의 id를 받아서 호출

✍ TodosContainer.js

0개의 댓글