본문 바로가기

Libraries/React

[React] useReducer를 코드에 적용하기 (emotion diary 프로젝트 2탄)

728x90

 

useReducer 개념을 알아야 이해가 가기 때문에 아래 게시글을 보고 오시길 바랍니다!

 

https://dev-ini.tistory.com/89

 

[React] useReducer로 복잡한 상태변화 로직을 컴포넌트로부터 분리하기

useReduer를 사용해서 복잡한 상태변화 로직을 컴포넌트로부터 분리하기 useReducer 위 사진에서 보다시피, App.js 컴포넌트 안에 굉장히 많은 상태변화함수 (onCreate, onEdit, onRemove)가 존재하는 상태이다

dev-ini.tistory.com

 

 

 


 

 

 

 1. reducer 함수를 전달하고, 기본 state 빈배열로 설정한다. 

 

 App.js 

import React, { useReducer } from "react";
import "./App.css";
import { BrowserRouter, Route, Routes } from "react-router-dom";

import Home from "./pages/Home";
import New from "./pages/New";
import Edit from "./pages/Edit";
import Diary from "./pages/Diary";

function App() {
  const [data, dispatch] = useReducer(reducer, []); // (1) reducer 함수 전달, 기본 state는 빈배열

  return (
    <BrowserRouter>
      <div className="App">
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/new" element={<New />} />
          <Route path="/edit" element={<Edit />} />
          <Route path="/diary/:id" element={<Diary />} />
        </Routes>
      </div>
    </BrowserRouter>
  );
}

export default App;

 

 

 

 2. reducer 함수를 구현한다. 

import React, { useReducer } from "react";
import "./App.css";
import { BrowserRouter, Route, Routes } from "react-router-dom";

import Home from "./pages/Home";
import New from "./pages/New";
import Edit from "./pages/Edit";
import Diary from "./pages/Diary";

// (2) reducer 함수 구현
const reducer = (state, action) => {
  // 2개의 파라미터 (state, action) 를 받음
  let newState = []; // (3) 배열 만들기
  switch (
    action.type // (4) switch 케이스 작성
  ) {
    case "INIT": {
      // (5)
      return action.data;
    }
    case "CREATE": {
      // (6)
      const newItem = {
        ...action.data,
      };
      newState = [newItem, ...state]; // (7) newState라는 변수에 새로운 state로 바뀔 값을 넣어줌.
      break; // (10)
    }
    case "REMOVE": {
      // (11)
      newState = state.filter((it) => it.id !== action.targerId);
      break; // (12)
    }
    case "EDIT": {
      // (13) 전체를 다 바꿀 수 있게 하기 (action.data)
      newState = state.map((it) =>
        it.id === action.data.id ? { ...action.data } : it
      );
      break; // (14)
    }

    default: // (9)
      return state;
  }
  return newState; // (8)
};

function App() {
  const [data, dispatch] = useReducer(reducer, []); // (1) reducer 함수 전달, 기본 state는 빈배열

  return (
    <BrowserRouter>
      <div className="App">
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/new" element={<New />} />
          <Route path="/edit" element={<Edit />} />
          <Route path="/diary/:id" element={<Diary />} />
        </Routes>
      </div>
    </BrowserRouter>
  );
}

export default App;

 

 

 

 3. dispatch 함수를 만든다. 

import React, { useReducer, useRef } from "react";
import "./App.css";
import { BrowserRouter, Route, Routes } from "react-router-dom";

import Home from "./pages/Home";
import New from "./pages/New";
import Edit from "./pages/Edit";
import Diary from "./pages/Diary";

// (2) reducer 함수 구현
const reducer = (state, action) => {
  // 2개의 파라미터 (state, action) 를 받음
  let newState = []; // (3) 배열 만들기
  switch (
    action.type // (4) switch 케이스 작성
  ) {
    case "INIT": {
      // (5)
      return action.data;
    }
    case "CREATE": {
      // (6)
      const newItem = {
        ...action.data,
      };
      newState = [newItem, ...state]; // (7) newState라는 변수에 새로운 state로 바뀔 값을 넣어줌.
      break; // (10)
    }
    case "REMOVE": {
      // (11)
      newState = state.filter((it) => it.id !== action.targerId);
      break; // (12)
    }
    case "EDIT": {
      // (13) 전체를 다 바꿀 수 있게 하기 (action.data)
      newState = state.map((it) =>
        it.id === action.data.id ? { ...action.data } : it
      );
      break; // (14)
    }

    default: // (9)
      return state;
  }
  return newState; // (8)
};

function App() {
  const [data, dispatch] = useReducer(reducer, []); // (1) reducer 함수 전달, 기본 state는 빈배열

  const dataId = useRef(0); // (15)

  // CREATE
  const onCreate = (date, content, emotion) => {
    // (16) 언제 작성된 일기인지까지 받을 것이기 때문에 date까지 받아줌
    dispatch({
      type: "CREATE",
      data: {
        // (17)
        id: dataId.current,
        date: new Date(date).getTime(),
        content,
        emotion,
      },
    });
    dataId.current += 1; // (18)
  };

  // REMOVE
  const onRemove = (targetId) => {
    // (19)
    dispatch({ type: "REMOVE", targetId });
  };

  // EDIT
  const onEdit = (targetId, date, content, emotion) => {
    // (20)
    dispatch({
      type: "EDIT",
      data: {
        id: targetId,
        date: new Date(date).getTime(),
        content,
        emotion,
      },
    });
  };

  return (
    <BrowserRouter>
      <div className="App">
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/new" element={<New />} />
          <Route path="/edit" element={<Edit />} />
          <Route path="/diary/:id" element={<Diary />} />
        </Routes>
      </div>
    </BrowserRouter>
  );
}

export default App;

 

 

 

 4. 상태관리로직에 context를 만들어서 data state를 컴포넌트 트리 전역에 공급하기 

import React, { useReducer, useRef } from "react";
import "./App.css";
import { BrowserRouter, Route, Routes } from "react-router-dom";

import Home from "./pages/Home";
import New from "./pages/New";
import Edit from "./pages/Edit";
import Diary from "./pages/Diary";

// (2) reducer 함수 구현
const reducer = (state, action) => {
  // 2개의 파라미터 (state, action) 를 받음
  let newState = []; // (3) 배열 만들기
  switch (
    action.type // (4) switch 케이스 작성
  ) {
    case "INIT": {
      // (5)
      return action.data;
    }
    case "CREATE": {
      // (6)
      const newItem = {
        ...action.data,
      };

      newState = [newItem, ...state]; // (7) newState라는 변수에 새로운 state로 바뀔 값을 넣어줌.
      break; // (10)
    }
    case "REMOVE": {
      // (11)
      newState = state.filter((it) => it.id !== action.targerId);
      break; // (12)
    }
    case "EDIT": {
      // (13) 전체를 다 바꿀 수 있게 하기 (action.data)
      newState = state.map((it) =>
        it.id === action.data.id ? { ...action.data } : it
      );
      break; // (14)
    }
    default: // (9)
      return state;
  }
  return newState; // (8)
};

export const DiaryStateContext = React.createContext(); // (21)
export const DiaryDispatchContext = React.createContext(); // (23)

function App() {
  const [data, dispatch] = useReducer(reducer, []); // (1) reducer 함수 전달, 기본 state는 빈배열

  const dataId = useRef(0); // (15)
  // CREATE
  const onCreate = (date, content, emotion) => {
    // (16) 언제 작성된 일기인지까지 받을 것이기 때문에 date까지 받아줌
    dispatch({
      type: "CREATE",
      data: {
        // (17)
        id: dataId.current,
        date: new Date(date).getTime(),
        content,
        emotion,
      },
    });
    dataId.current += 1; // (18)
  };

  // REMOVE
  const onRemove = (targetId) => {
    // (19)
    dispatch({ type: "REMOVE", targetId });
  };

  // EDIT
  const onEdit = (targetId, date, content, emotion) => {
    // (20)
    dispatch({
      type: "EDIT",
      data: {
        id: targetId,
        date: new Date(date).getTime(),
        content,
        emotion,
      },
    });
  };

  return (
    <DiaryStateContext.Provider value={data}>
      {" "}
      {/* (22) */}
      <DiaryDispatchContext.Provider value={{ onCreate, onEdit, onRemove }}>
        {" "}
        {/* (24) */}
        <BrowserRouter>
          <div className="App">
            <Routes>
              <Route path="/" element={<Home />} />
              <Route path="/new" element={<New />} />
              <Route path="/edit" element={<Edit />} />
              <Route path="/diary/:id" element={<Diary />} />
            </Routes>
          </div>
        </BrowserRouter>
      </DiaryDispatchContext.Provider>
    </DiaryStateContext.Provider>
  );
}

export default App;

 

728x90