23/11/28 til 리덕스 타임어택
2023. 11. 29. 07:57ㆍ카테고리 없음
2시간 이내에 투두리스트를 리덕스로 동작하게하기
<configstore.js> // 일단 터미널에 yarn add redux react-redux 를 받는다.
import { combineReducers, createStore } from "redux"; // 일단 터미널에 yarn add redux react-redux
import todos from "../modules/todos"; //리덕스에서 컴바인리듀서와 크리에이트리듀서 임포트
const rootReducer = combineReducers({ todos }); //컴바인 리듀서는 모든 리듀서들을 {a,b,c} 같은객체를
//인자로 받아서 합친다.const store = createStore(rootReducer); //합친 리듀서들로 크리에이트스토어를 통해 스토어생성
export default store; // 스토어를 익스포트한다.
<todos.js> 리듀서와 액션크리에이트등을 담는 파일
import { type } from "@testing-library/user-event/dist/type";
const initialState = [ // state의 초기상태
{
id: "아이디1",
title: "제목1",
contents: "내용1",
isDone: true,
},
{
id: "아이디2",
title: "제목2",
contents: "내용2",
isDone: false,
},
{
id: "아이디3",
title: "제목3",
contents: "내용3",
isDone: false,
},
];
const ADD_TODO = "todos/ADD_TODO"; //코드의 휴먼에러를 줄이기 위해서?
const DELETE_TODO = "todos/EDIT_TODO"; //상수의 변수명 선언
const SWITCH_TODO = "todos/SWITCH_TODO";
export const addTodo = (payload) => { // 이 형태들이 액션 크리에이터객체 들이다
return { type: ADD_TODO, payload }; //나중에 익스포트해서 다른 jsx파일 등에서
};
export const deleteTodo = (payload) => { //이 함수들을 호출해서 사용할 예정
return { type: DELETE_TODO, payload }; //호출시에 인자를 payload로써 받아서
};
export const switchTodo = (payload) => { //그 페이로드를 요소로 같는 객체를 반환한다.
return { type: SWITCH_TODO, payload }; //객체의 요소는 위에서 작성한 타임과 페이로드가 있다.
};
const todos = (state = initialState, action) => { //이게 리듀서 인자로 현재 상태인 스테이트와 액션을
switch (action.type) { //받는다. 액션은 두개의 요소를 갖는데 타입과 페이로드이다.
case ADD_TODO:
const newtodo = action.payload; //위에 액션크리에이트객체가 호출될시 받은 타입
return [newtodo, ...state]; //타입에 따라 스위치문의 case가 달라지게 되고
case DELETE_TODO: //해당케이스에서 받아놨던 payload값이 로직에 적용되여
const todoId = action.payload; //결과 값을 리턴한다.
return state.filter((todo) => todo.id !== todoId);
case SWITCH_TODO:
const { id, isDone } = action.payload; //삭제로직과 스위치 로직이 작동 안됨 ㅜㅜ
return state.map((todo) => {
if (todo.id === id) {
return { ...todo, isDone: !isDone };
}
});
default:
return state;
}
};
export default todos;
<Router.jsx> 리액트 라우터 돔을 터미널에서 받고 사용한다.
import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "../pages/Home"; // 페이지는 홈과 디테일을 쓸 예정이라 두개를 임포트
import Detail from "../pages/Detail"; //홈과 디테일 페이지는 만들예정
export default function Router() {
return (
<>
<BrowserRouter> //브라우저라우터 라우츠 라우트는 아래처럼 쓴다.
<Routes>
<Route path="/" element={<Home />}></Route>
<Route path="/:id" element={<Detail />}></Route> //사실 /:id 이거 잘 못쓰겠음 ㅜㅜ
</Routes>
</BrowserRouter>
</>
);
}
<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 "./config/configstore"; //내가만든 스토어 임포트
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Provider store={store}> //app 작스를 프로바이더 태그로 감싸주고 스토어 를 저런 형식으로
<App /> //App에게 넘긴다.
</Provider>
);
// 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();
<Home.jsx> 메인 페이지이다.
import { nanoid } from "nanoid"; // 나노아이디를 사용
import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { addTodo, deleteTodo, switchTodo } from "../modules/todos"; //액션크리에이터객체 임포트
import { useNavigate } from "react-router-dom"; // 사용할 꺼니까
//화면 이동을 위한 유즈네이게이트export default function Home() {
const [title, setTitle] = useState(""); //타이틀과 컨텐츠는 여기서만 사용할꺼니까
const [contents, setContents] = useState(""); //간단하게 유즈스테이트로 인풋값에서 받아옴
const navigate = useNavigate();
const disPatch = useDispatch(); //유즈디스페치 이 훅을 통해 액션크리에이터를 동작
const todos = useSelector((state) => state.todos); //하여 화면을 리랜더링한다.
//유즈 셀렉터 이 것을통해 스토어에서 정보를 가져온다. const doingtodo = todos.filter(function (todo) {
return todo.isDone === false;
});
const donetodo = todos.filter(function (todo) {
return todo.isDone === true;
});
return (
<>
<h1>투두리스트</h1>
<div>
<form
onSubmit={(e) => {
e.preventDefault();
const newTodo = {
id: nanoid(),
title: title,
contents,
isDone: false,
};
disPatch(addTodo(newTodo));
}}
>
<span>제목</span>
<input
value={title}
onChange={(e) => {
setTitle(e.target.value);
}}
/>
<span>내용</span>
<input
value={contents}
onChange={(e) => {
setContents(e.target.value);
}}
/>
<button>추가하기</button>
</form>
</div>
<div>
<h1>해야할 투두</h1>
<>
{doingtodo.map((todo) => {
return (
<section>
<div>id :{todo.id}</div>
<div>제목 :{todo.title}</div>
<div>내용 :{todo.contents}</div>
<div>진행상태 :{todo.isDone ? "완료" : "진행중"}</div>
<div>
<button
onClick={() => {
disPatch(deleteTodo(todo.id)); //이런식으로 디스패치에
> //액션객체를 넣고 액션객체에 patload를 넘긴다.
삭제하기
</button>
<button
onClick={() => {
disPatch(switchTodo(todo)); //페이로드는 어떤 case를 동작할꺼냐에 따라
}} //받을게 달라진ㄴ다.
>
완료
</button>
<button
onClick={() => {
navigate(`/${todo.id}`); //네비게이트 이렇게 쓰는거 맞나?
}} //이거 공부 다시해야되는데 아는사람 댓글좀 주세요
>
상세 페이지 //브라우저에서 상세페이지 이동이 작동 안함 ㅜㅜ 망함
</button>
</div>
</section>
);
})}{" "}
</>
</div>
<div>
<h1>완료된 투두</h1>
<>
{donetodo.map((todo) => {
return (
<section>
<div>id :{todo.id}</div>
<div>제목 :{todo.title}</div>
<div>내용 :{todo.contents}</div>
<div>진행상태 :{todo.isDone ? "완료" : "진행중"}</div>
<div>
<button
onClick={() => {
disPatch(deleteTodo(todo.id));
}}
>
삭제하기
</button>
<button
onClick={() => {
disPatch(switchTodo(todo));
}}
>
진행
</button>
<button
onClick={() => {
navigate(`/${todo.id}`);
}}
>
상세 페이지
</button>
</div>
</section>
);
})}{" "}
</>
</div>
</>
);
}
<Detail.jsx> 투두들의 상세 페이지
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { useLocation, useNavigate, useParams } from "react-router-dom";
import { deleteTodo, switchTodo } from "../modules/todos";
export default function Detail() {
const todos = useSelector((state) => state.todos);
const location = useLocation();
const params = useParams(); //아니 진짜 유즈 파람스 다시 해봐야하는데 .
const navigate = useNavigate();
const disPatch = useDispatch();
return (
<>
<div>
{todos.id === params
? todos.map((todo) => {
return (
<>
<div>id :{todo.id}</div>
<div>제목 :{todo.title}</div>
<div>내용 :{todo.contents}</div>
<div>진행상태 :{todo.isDone ? "완료" : "진행중"}</div>
<div>
<button
onClick={() => {
disPatch(deleteTodo(todo.id));
navigate("/");
}}
>
삭제하기
</button>
<button
onClick={() => {
disPatch(switchTodo(todo));
}}
>
이동하기
</button>
</div>
</>
);
})
: null}
</div>
<div>
<button
onClickCapture={() => {
navigate("/");
}}
>
이전화면으로
</button>
</div>
</>
);
}
타임어택으로 리덕스를 해보긴했는데 이해도는 높아졌는데 숙련도가 너무 낮다. 큰일이다.