Todolist Redux Frontend

심재원·2023년 11월 27일
1

참고

redux dev tools

Backend

Terminal

npm i cors
npm run dev

FrontEnd Redux Setting

git clone tailwindcss frontend파일 설치
remove remote

Terminal 새로 열고

cd frontend
npm i @reduxjs/toolkit react-redux

redux/appSlice.js folder/file 생성

appSlice.js 기본 redux code

import { createSlice } from "@reduxjs/toolkit";

const appSlice = createSlice({
  name: "appSlice",
  initialState: {},
  reducers: {},
  extraReducers: {},
});

export default appSlice;

store.js file 생성 & code

import { configureStore } from "@reduxjs/toolkit";
import appSlice from "./appSlice";

const store = configureStore({
  reducer: {
    appReducer: appSlice.reducer,
  },
});

export default store;

index.js 이동 및 코드 추가

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

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

Terminal

cd frontend
npm i axios

appThunk.js file 생성 및 코드

import { createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";

export const getTodos = createAsyncThunk("appSlice/getTodos", async () => {
  const response = await axios.get("http://localhost:3010/todos");

  console.log(response);  -> 콘솔은 잘 되는지 확인하기 위함!

  return response.data.todos;
});

AppSlice.js 이동 및 코드 수정

import { createSlice } from "@reduxjs/toolkit";
import { getTodos } from "./appThunk";

const appSlice = createSlice({
  name: "appSlice",
  initialState: {
    todos: null,
    isLoading: false,
  },

  extraReducers: (builder) => {
    builder.addCase(getTodos.pending, (state) => {
      state.isLoading = true;
    });
    builder.addCase(getTodos.fulfilled, (state, action) => {
      state.todos = action.payload;
      state.isLoading = false;
    });
    builder.addCase(getTodos.rejected, (state) => {
      state.isLoading = false;
    });
  },
});

export default appSlice;

App.jsx file code

import { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { getTodos } from "./redux/appThunk";

const App = () => {
  const { todos } = useSelector((state) => state.appReducer);
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(getTodos());
  }, []);

  useEffect(() => {
    console.log(todos);
  }, [todos]);

  return <div className="bg-red-100">Hello, React!</div>;
};

export default App;

Backend - app.js file

const express = require("express");
const cors = require("cors");
const todosRouter = require("./routes/todos");

const app = express();

const port = 3010;

app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use("/todos", todosRouter);

app.get("/", (req, res) => {
  return res.send("Hello, Express!");
});

app.listen(port, () => {
  console.log(`🚀 Server is listening on port : ${port}`);
});

appThunk.js code

import { createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";

export const getTodos = createAsyncThunk("appSlice/getTodos", async () => {
  const response = await axios.get("http://localhost:3010/todos");

  return response.data.todos;
});

components/CreateTodo.jsx 생성 및 코드

import { useState } from "react";
import { useDispatch } from "react-redux";
import { createTodo } from "../redux/appThunk";

const CreateTodo = () => {
  const [newTodo, setNewTodo] = useState("");
  const dispatch = useDispatch();

  const onSubmitCreateTodo = (e) => {
    e.preventDefault();

    if (!newTodo) return;

    dispatch(createTodo({ title: newTodo }));
  };

  return (
    <form onSubmit={onSubmitCreateTodo}>
      <input
        type="text"
        value={newTodo}
        onChange={(e) => setNewTodo(e.target.value)}
      />
      <input type="submit" value="생성" />
    </form>
  );
};

export default CreateTodo;

appThunk.js Input

import { createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";

export const getTodos = createAsyncThunk("appSlice/getTodos", async () => {
  const response = await axios.get("http://localhost:3010/todos");

  return response.data.todos;
});

export const createTodo = createAsyncThunk(
  "appSlice/createTodo",
  async ({ title }) => {
    const response = await axios.post(
      "http://localhost:3010/todos",
      { title },
      {
        headers: {
          "Content-Type": "application/json",
        },
      }
    );

    return response.data.todo;
  }
);

appSlice.js Code

import { createSlice } from "@reduxjs/toolkit";
import { createTodo, getTodos } from "./appThunk";

const appSlice = createSlice({
  name: "appSlice",
  initialState: {
    todos: null,
    isLoading: false,
  },
  extraReducers: (builder) => {
    builder.addCase(getTodos.pending, (state) => {
      state.isLoading = true;
    });
    builder.addCase(getTodos.fulfilled, (state, action) => {
      state.todos = action.payload;
      state.isLoading = false;
    });
    builder.addCase(getTodos.rejected, (state) => {
      state.isLoading = false;
    });
    builder.addCase(createTodo.pending, (state) => {
      state.isLoading = true;
    });
    builder.addCase(createTodo.fulfilled, (state, action) => {
      state.todos = [...state.todos, action.payload];
      state.isLoading = false;
    });
    builder.addCase(createTodo.rejected, (state) => {
      state.isLoading = false;
    });
  },
});

export default appSlice;

App.jsx code

import { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { getTodos } from "./redux/appThunk";
import CreateTodo from "./components/CreateTodo";

const App = () => {
  const { todos } = useSelector((state) => state.appReducer);
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(getTodos());
  }, []);

  useEffect(() => {
    console.log(todos);
  }, [todos]);

  return (
    <div className="bg-red-100">
      <CreateTodo />
    </div>
  );
};

export default App;

0개의 댓글