Notice
Recent Posts
Recent Comments
Link
개발자로 전직하자
[TIL] 36일차(20240202) - [React] Context API, Redux 복습 본문
목차
#1 ContextAPI로 로그인 상태관리
import React, { createContext, useMemo, useState } from "react";
const initialAuthContextValue = {
isLoggedIn: false,
toggleLogIn: () => {},
userId: null,
setUserId: () => {},
};
export const AuthContext = createContext(initialAuthContextValue);
export function AuthProvider({ children }) {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [userId, setUserId] = useState(null);
console.log("리렌더 AuthProvider");
const value = useMemo(
() => ({
isLoggedIn,
toggleLogIn: () => setIsLoggedIn((prev) => !prev),
userId,
setUserId,
}),
[userId, isLoggedIn]
);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
// App.js
import { BrowserRouter, Route, Routes } from "react-router-dom";
import "./App.css";
import { AuthProvider } from "./contexts/auth.context";
import HomePage from "./pages/HomePage";
function App() {
console.log("리렌더 App");
return (
<BrowserRouter>
<AuthProvider>
<Routes>
<Route path="/" element={<HomePage />} />
</Routes>
</AuthProvider>
</BrowserRouter>
);
}
export default App;
// Header에서 로그인 여부에 따른 변화주기
import React, { useContext } from "react";
import { AuthContext } from "../contexts/auth.context";
function Header() {
const authContext = useContext(AuthContext);
const { isLoggedIn, toggleLogIn } = authContext;
console.log("리렌더 Header");
return (
<header className="h-14 border">
<button onClick={toggleLogIn}>로그인 토글</button>
<div>로그인 여부: 로그인 {!isLoggedIn && "안 "}됨</div>
</header>
);
}
export default Header;
#2 Redux로 장바구니 기능 묘사
// cart.reducer.js
export const ADD_ITEM = "cart/addItem";
export const REMOVE_ITEM = "cart/removeItem";
export const addItemActionCreator = (payload) => ({ type: ADD_ITEM, payload });
export const removeItemActionCreator = (payload) => ({
type: REMOVE_ITEM,
payload,
});
const initialState = {
items: [],
totalPrice: 0,
};
export default function cartReducer(state = initialState, action) {
const newState = { ...state };
if (action.type === ADD_ITEM) {
const newItem = action.payload;
const newItems = [...state.items, newItem];
newState.items = newItems;
} else if (action.type === REMOVE_ITEM) {
const itemIdToRemove = action.payload;
const newItems = state.items.filter((item) => item.id !== itemIdToRemove);
newState.items = newItems;
}
return newState;
}
// user.reducer.js (immer활용)
import { produce } from "immer";
const initialState = {
isLoggedIn: false,
lastVisitedAt: null,
grade: null,
profile: {
nickname: null,
age: null,
location: null,
avatar: null,
experiences: [],
},
friends: [],
likedGoods: [],
};
const LOG_IN = "user/logIn";
const LOG_OUT = "user/logOut";
const UPDATE_EXPERIENCE = "user/updateExperience";
const UPDATE_AVATAR_SRC = "user/updateAvatarSrc";
const ADD_FRIEND = "user/addFriend";
const REMOVE_FRIEND = "user/removeFriend";
const LIKE = "user/like";
const UNLIKE = "user/unlike";
export const logIn = () => ({ type: LOG_IN });
export const logOut = () => ({ type: LOG_OUT });
export const updateExperience = (payload) => ({
type: UPDATE_EXPERIENCE,
payload,
});
export const updateAvatarSrc = (payload) => ({
type: UPDATE_AVATAR_SRC,
payload,
});
export const addFriend = (payload) => ({ type: ADD_FRIEND, payload });
export const removeFriend = (payload) => ({ type: REMOVE_FRIEND, payload });
export const like = (payload) => ({ type: LIKE, payload });
export const unlike = (payload) => ({ type: UNLIKE, payload });
export function userReducer(state = initialState, action) {
if (action.type === UPDATE_EXPERIENCE) {
const newState = produce(state, (draft) => {
const { id, data } = action.payload;
const indexToUpdate = draft.profile.experiences.findIndex(
(experience) => experience.id === id
);
draft.profile.experiences[indexToUpdate] = data;
});
return newState;
} else if (action.type === ADD_FRIEND) {
const newState = produce(state, (draft) => {
const newFriend = action.payload;
draft.friends.push(newFriend);
});
return newState;
} else if (action.type === REMOVE_FRIEND) {
const friendIdToRemove = action.payload;
const newState = {
...state,
friends: state.friends.filter((friend) => friend.id !== friendIdToRemove),
};
return newState;
}
}
// store
import { configureStore } from "@reduxjs/toolkit";
import cartReducer from "./reducers/cart.reducer";
const store = configureStore({
reducer: {
cart: cartReducer,
},
});
export default store;
// App.js
import { nanoid } from "nanoid";
import { useDispatch, useSelector } from "react-redux";
import "./App.css";
import {
addItemActionCreator,
removeItemActionCreator,
} from "./store/reducers/cart.reducer";
function App() {
const items = useSelector((state) => state.cart.items);
const dispatch = useDispatch();
const handleClickAddItem = () => {
const id = nanoid();
const amount = 1;
const item = { id, amount };
const action = addItemActionCreator(item);
dispatch(action);
};
const handleClickRemoveItem = (itemId) => () => {
const action = removeItemActionCreator(itemId);
dispatch(action);
};
return (
<div className="App">
<button onClick={handleClickAddItem}>랜덤 상품 추가하기</button>
<ul>
{items.map((item) => (
<li key={item.id}>
<span>{item.id}</span>
<button onClick={handleClickRemoveItem(item.id)}>제거하기</button>
</li>
))}
</ul>
</div>
);
}
export default App;
#3 Redux Toolkit 사용
// user.reducer.js (toolkit사용)
import { createSlice } from "@reduxjs/toolkit";
const userSlice = createSlice({
initialState: {
isLoggedIn: false,
lastVisitedAt: null,
grade: null,
profile: {
nickname: null,
age: null,
location: null,
avatar: null,
experiences: [],
},
friends: [],
likedGoods: [],
},
name: "user2222",
reducers: {
toggleLogin(state, action) {
state.isLoggedIn = !state.isLoggedIn;
},
updateExperience(state, action) {
const { id, data } = action;
const experienceIndexToUpdate = state.profile.experiences.findIndex(
(experience) => experience.id === id
);
state.profile.experiences[experienceIndexToUpdate] = data;
},
},
});
export const userReducer = userSlice.reducer;
export const { toggleLogin, updateExperience } = userSlice.actions;
// 각각이 액션크리에이터에요.
#4 실습(과제) : 쇼핑몰 구현하기
'유데미X사람인 부트캠프 > TIL' 카테고리의 다른 글
[TIL] 41 ~ 44일차(20240213 ~ 16) - Node.js / Express.js / 테이블 설계, ORM - PQ, Prisma (0) | 2024.02.19 |
---|---|
[TIL] 37 ~ 40일차(20240205 ~ 08) - Git, TypeScript / Next.js (1) | 2024.02.12 |
[TIL] 35일차(20240201) - [React] Redux(전역 상태 관리) (0) | 2024.02.01 |
[TIL] 34일차(20240131) - [React] 기초 익히기 / Routing 구현 (0) | 2024.02.01 |
[TIL] 33일차(20240130) - [React] 기초 익히기-2 (0) | 2024.01.30 |