[220711 / Day 40] ์ผํ๋ชฐ ๋ง๋ค๊ธฐ 2
! ์ค๋ ํ ๊ฒ !
- ๋ก๊ทธ์ธ ๋ก๊ทธ์์ : ๋ก๊ทธ์ธํ๋ฉด ์ํ๋ช ํ์ด์ง ๋จ๋๋ก
- ์ ๋ฒ์ ์ฅ๋ฐ๊ตฌ๋์์ ์ญ์ ์ ์๋๊ฑฐ ์์
- ๋ผ์ฐํ ์ค๋ช
- ์์ธํ์ด์ง ์ค๋ช
1. ๋งํฌ๋ฅผ ๊ฑฐ๋ ๋ฐฉ๋ฒ
์ฒซ๋ฒ์งธ ๋ฐฉ๋ฒ) link ์ปดํฌ๋ํธ ์ฌ์ฉ : ํ๋ฉด์์๋ a ํ๊ทธ๋ก ๋ณํ → ๊ทธ๋ฅ a ํ๊ทธ์ฒ๋ผ ์ฌ์ฉํ๋ ์ํฉ์ผ ๋
๋๋ฒ์งธ ๋ฐฉ๋ฒ) ํจ์๋ก ํธ์ถํด์ฃผ๋ ๋ฐฉ๋ฒ : useNavigate์ฌ์ฉ → ํจ์๋ฅผ ํธ์ถํด์ค์ผ ํ๋ ์ํฉ์ผ ๋
- routes ํ๋ ๊ฑด app.js , index.js ๋ ๋ค ์๊ด์์
1) main.js ์์ ํ์ฌ์๊ฐ ํ์ด์ง ๋๋ฅด๋ฉด ๊ทธ ํ์ด์ง๋ก ๋์ด๊ฐ๋๋ก
- import { Link } from 'react-router-dom';
- <Link to='/company'>ํ์ฌ์๊ฐ ํ์ด์ง</Link>
2) company.js ์์ ๋ฉ์ธํ์ด์ง๋ก ์ด๋ ๋๋ฅด๋ฉด ๊ทธ ํ์ด์ง๋ก ๋์ด๊ฐ๋๋ก
- import { useNavigate } from 'react-router-dom';
- <span onClick={goToMain}>๋ฉ์ธํ์ด์ง๋ก ์ด๋</span>
const navigate = useNavigate();
const goToMain = () => {
navigate('/')
}
2. ? : ์ฟผ๋ฆฌ ๊ฐ
- uses์์นํ : query ๊ฐ ๊ฐ์ ธ์ฌ ์ ์๊ณ ์ ์ฟผ๋ฆฌ
- query ๊ฐ : url ๋ค์ ์ถ๊ฐ์ ์ธ ์ ๋ณด๋ฅผ ์ ๋ฌํ๊ณ ์ถ์ ๋ ์ฌ์ฉ
- usestate ์ ๋น์ทํ๊ฒ ์ฌ์ฉ
1) app.js ์์ product.js ๋ผ์ฐํธ
2) product.js
- import { useSearchParams } from 'react-router-dom'
- let [query,setQuery]=useSearchParams();
- console.log('query ๊ฐ', query.get('page'))
- ์ฌ๊ธฐ์ get ์ ์ด๋ค ๊ฑธ ๊ฐ์ ธ์ค๋ ๋ฉ์๋ page ์ ํด๋นํ๋ ํค๊ฐ์ ๊ฐ์ ธ์ค๊ฒ ๋ค๋ ๋ป
- http://localhost:3000/product?page=1&num=10 → ํ์ด์ง๋ 1, num์ 10 ์ธ๋ฐ ์ด๊ฑธ๋ก ์ฃผ์ ์ ๋ ฅํ์ ๋ ์ฝ์์ query ๊ฐ 1 ์ด๋ผ๊ณ ๋ธ
3) main.js
- import useNavigate
- const navigate = useNavigate();
const goToProduct = () =>{
navigate('/product?page=1&num=10&name=dd') // ๋ณดํต์ ๋ณ์๋ก ๋ค์ด๊ฐ
/* navigate(`/product?page=${id}&num=${num}&name=${name}`) -> ์ด๋ฐ ์์ผ๋ก ๋ค์ด๊ฐ */
}
- <button onClick={goToProduct}>์ํํ์ด์ง ๊ฐ๊ธฐ</button>
3. ์์ธํ์ด์ง ๋ง๋ค๊ธฐ
1) ProductDetail.js ํ์ผ ์์ฑ
- app.js ์ ProductDetail route
- useNavigate ๋ฅผ import ํด์ฃผ๊ธฐ
- const navigate = useNavigate();
- <button onClick={goToProduct}>์ํํ์ด์ง ๊ฐ๊ธฐ</button>
const goToProduct = () =>{
navigate('/product?page=1&num=10&name=dd') // ๋ณดํต์ ๋ณ์๋ก ๋ค์ด๊ฐ
/* navigate(`/product?page=${id}&num=${num}&name=${name}`) -> ์ด๋ฐ ์์ผ๋ก ๋ค์ด๊ฐ */
}
2) restfull routes : https://woojinger.tistory.com/32
- api ๋์์ธ ํจํด
- https://learn.co/lessons/sinatra-restful-routes-readme : Routes Overview ๋ณด๊ธฐ, url ๋์์ธ ๊ถ๊ณ ์ฌํญ
- ์์ธํ์ด์ง ํ์๋ก :id ์ธ๊ฑฐ์, id ๋ ๋ผ์ฐํธ์ ํ๋ผ๋ฏธํฐ๋ก ๋ณ์ ๊ฐ์ ๊ฐ๋ , ์ด๋ค ๊ฐ์ด ๋ค์ด์๋ ๋ฌด์กฐ๊ฑด ์์ธํ์ด์ง๋ฅผ ํ์ํด์ค
- /product/:id ๋ ์ด ์์ด๋ ๊ฐ์ ๊ฐ์ง ์์ดํ ์ ๋ณด์ฌ์ค๋ค๋ ๋ป
3) app.js ์ restfull routes ์ ์ฉ
- <Route path='/product:id' element={<ProductDetail />} />
- import ProductDetail from './pages/ProductDetail';
4) ProductDetail.js
- import { useSearchParams } from 'react-router-dom'
- const params = useParams();
- id ๊ฐ key ๊ฐ, value ๊ฐ id
4. ๋ก๊ทธ์ธ ํ์ด์ง ๊ตฌํ
1) ๊ธฐ๋ณธํ ๋ง๋ค๊ธฐ
- User.js ์ปดํฌ๋ํธ ์์ฑ
- route > RedirectsRoute.js ์์ฑ
2) Redirects
๋ฐฉํฅ์ ๋ค๋ฅธ ํ์ด์ง๋ก ๋๋ ค ์ฃผ๋ ๊ฒ
3) app.js
- <Route path='/login' element={<Login />} /> ์ถ๊ฐ
- <Route path='/product/:id' element={<UserRedirects />} /> ์ถ๊ฐ
4) RedirectsRoute.js
import React from 'react';
import Detail from '../components/Detail';
import { Navigate } from 'react-router-dom'
import { useSelector } from 'react-redux/es/exports';
const UserRedirects = () => {
const user = useSelector((state)=>state.user.value)
return user === true ? <Detail /> : <Navigate to='/login' />;
};
export default UserRedirects;
5. ์๋ฌ ๋ฌ๋ ์ฅ๋ฐ๊ตฌ๋ react12 ์์ ์ด์ด์
1) CartItem.js
const restItems = cart.filter((ele, index) => {
let indexNum;
if (ele.id === item.id) {
indexNum = index;
}
return indexNum;
})
→ ์ง์ฐ๊ณ ๋ค์
- const restItems = cart.filter((ele, index) => ele.id === item.id) ๋ก ์์
- ele.id === item.id : ์ผ์นํ๋ ๊ฒ์ ํ๋์ด๊ธฐ ๋๋ฌธ์ ๊ณ์ index๋ 0 ๋ฒ์ผ ๊ฒ์
2) cartSlice.js
- deleteCart ์์ const num = state.findIndex (์ด๋ ์ด์ ๋ฉ์๋) ๋ก ๊ฒ์ฌํ ๊ฒ์
- const num = state.findIndex((ele)=>ele.id===action.payload[0].id)
console.log(action.payload)
/* 0: {id: 1, product_name: '๊ฒ์ ์นผ๋ผ ์ค์จํฐ', price: 35000, product_img: 'https://picsum.photos/200', is_checked: 'false'}
length: 1
[[Prototype]]: Array(0) */
- state.splice(num, 1) ๋ก ์์
- ์ง๋ ๋ฒ์ ์ ์ ๋๋์ง ์์์ผ ํจ
์ฅ๋ฐ๊ตฌ๋์ ๊ฐ์ ์ ๋ชป ๋ด๊ฒ
- state = state.push(action.payload); ์์
- console.log(action.payload.id) : ํด๋ฆญํ id ๊ฐ ๋ธ
- const equalItem = state.findIndex(ele=>ele.id===action.payload.id);
if(equalItem>=0){
alert ('์ฅ๋ฐ๊ตฌ๋์ ๋์ผํ ์ํ์ด ์์ต๋๋ค.')
}else{
state = state.push(action.payload);
}
→ ๊ณผ์ : ์ฅ๋ฐ๊ตฌ๋ ์ด ํฉ์ฐ ๊ตฌํ๊ธฐ
6. redux-persist : ๋ก์ปฌ์คํ ๋ฆฌ์ง ์ฌ์ฉํ ์ ์๊ฒ ๋ง๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- https://redux-toolkit.js.org/tutorials/overview ์ฐธ๊ณ
- npm install redux-persist : ์ค์น ๋จผ์
1) store ์ index.js
import storage from 'redux-persist' //๋ก์ปฌ
import storageSession from 'redux-persist/lib/storage/session' //์ธ์
- import { persistReducer } from 'redux-persist' : reducer ๊ฐ ์คํ๋ ๋ persist ๋ฅผ ๊ฐ์ด ์ฌ์ฉํ๊ฒ ๋ฌถ์ด์ ์ฌ์ฉํ ์ ์๊ฒ ํ๋ ๊ฒ
- import { configureStore, combineReducers } from '@reduxjs/toolkit' : combineReducers ์ฌ๋ฌ๊ฐ์ง reducer ๋ฅผ ๋ฌถ์ด์ ์ฌ์ฉํ ์ ์๊ฒ ํ๋ ๊ฒ(login reducer ๋ ๋ง๋ค ๊ฒ์ด๊ณ persist ๋ ๋ง๋ค ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ์ฌ์ฉํจ)
- persistConfig ๋ณ์ ๋ง๋ค๊ณ key: 'root', storage, ์ ๊ธฐ
- ์ฌ๊ธฐ์ key ๊ฐ์ด๋ localstorage ์ ์ ์ฅ๋ ๋์ key ๊ฐ
- const rootReducer = combineReducers({ cart : cartSlice, })
const persistedReducer = persistReducer(persistConfig, rootReducer)
// persistConfig ์ rootReducer ๋ฅผ ๋ฌถ์ด์ ์ฌ์ฉํ ์ ์๊ฒ ํด์ค,
redux-persist ๋ฅผ ์ฌ์ฉํด์ ๋ก์ปฌ์คํ ๋ฆฌ์ง์ state ์ ์ฅํ๋ฉด ํ์ด์ง๊ฐ ์๋ก๊ณ ์นจ ๋์ด๋ ์ด๊ธฐ๊ฐ(initialState)์ด ๋ก์ปฌ์คํ ๋ฆฌ์ง์ ์ ์ฅ๋ state ๊ฐ์ผ๋ก ๋์ฒด๋๊ธฐ ๋๋ฌธ์ ์ด๊ธฐํ๋์ง ์๋๋ค.
- const store = configureStore({ reducer : persistedReducer, }) ์ ์ ํ
export default configureStore({
reducer: {
cart: cartSlice
}
})
→ ์ง์ฐ๊ณ export default store; ๋ก ์์
2) src ํด๋์ index.js ํ์ผ
- import { PersistGate } from 'redux-persist/integration/react';
- let persistor = persistStore(store);
<PersistGate persistor={persistor}>
<App />
</PersistGate>
→ ์์
- import { persistStore } from "redux-persist";
3) store ํด๋์ index.js ํ์ผ
- middelware : ์ฌ๊ฐ, ํ ํฌ? ๋๊ฐ์ง๊ฐ ์์. redux ์์์ ๋น๋๊ธฐ์ฒ๋ฆฌ. ์ฌ๊ฐ๋ ๋ฐ๋ก ์ค์นํด์ผ ํ๊ณ ํ ํฌ๋ toolkit ์ ์์
7. ๋ก๊ทธ์ธ
1) Login.js ํ์ผ ์์ฑ
<form>
<div>
<div><label htmlFor='userId'>์์ด๋</label></div>
<div><input type="text" id="userId" placeholder='์์ด๋์ ๋ ฅ' /></div>
</div>
<div>
<div><label htmlFor='userPass'>๋น๋ฐ๋ฒํธ</label></div>
<div><input type="password" id="userPass" /></div>
</div>
<div>
<input type="submit" value="๋ก๊ทธ์ธ" />
</div>
</form>
→ ๊ธฐ๋ณธํ ์ ๋ ฅ
- app.js ์ <Route path='/login' element={<Login />} />
- Detail.js ํ์ผ ์์ฑ, ๊ธฐ๋ณธํ ์์ฑ
- route ํด๋ ์์ฑํด์ ๋ฐ์ UserRedirects.js ํ์ผ ์์ฑ
2) UserRedirects.js
import React from 'react';
import Detail from '../components/Detail';
import { Navigate } from 'react-router-dom'
import { useSelector } from 'react-redux/es/exports';
const UserRedirects = () => {
const user = useSelector((state)=>state.user.value)
return user === true ? <Detail /> : <Navigate to='/login' />;
};
export default UserRedirects;
3) app.js
- <Route path='/product/:id' element={<UserRedirects />} />
- import UserRedirects from './route/UserRedirects';
4) store > user > userSlice.js
import { createSlice } from '@reduxjs/toolkit'
const initialState = {
value: false,
}
export const userSlice = createSlice({
name: 'user', // reducer ์ ์ด๋ฆ
initialState, // ๋ฐ์ดํฐ์ ์ด๊ธฐ๊ฐ
reducers: { // ์ํ๊ฐ ๋ณํ๋ฉด ์ด๋ป๊ฒ ์คํ๋ ์ง ์ง์
login: (state, action) => {
state.value = action.payload;
action.type='SET_USER_LOGIN'
},
logout: (state, action) => {
state.value = action.payload;
action.type='SET_USER_LOGOUT'
},
},
})
export const { login, logout } = userSlice.actions
export default userSlice.reducer
→ ์ด๊ธฐ ์ธํ
5) store > index.js
- user:userSlice ์ถ๊ฐ
- import { userSlice } from './user/userSlice'; ์ถ๊ฐ
6) login.js
- <form onSubmit={(e)=>loginUser(e)}> ์์
- ๋ณ์ loginUser ์ถ๊ฐ
const loginUser = (e)=>{
e.preventDefault();
dispatch(login(true))
navigate('/')
}
7) nav.js
- import useNavigate, useDispatch, logout
const user=useSelector((state) => state.user.value)
const dispatch = useDispatch()
const navigate = useNavigate()
→ ์ถ๊ฐ
{
user ?
( <span className="user" onClick={()=>{dispatch(logout(false))}}>๋ก๊ทธ์์</span>) :
(<span className="user" onClick={() =>
navigate("/login")}>๋ก๊ทธ์ธ</span>)
}
→ ์ถ๋ ฅ๋์ด์ผ ํ๋ ๊ณณ์ ์ถ๊ฐ
8. ํ๋ผ์ด๋นํ์ด์ง ๋ฆฌ๋ค์ด๋ ํธ
1) ProductItem
const navigate = useNavigate();
const goToDetail=()=>{
navigate(`/product/${item.id}`)
}
→ ์ถ๊ฐ
- import { useNavigate } from 'react-router-dom';
- <div className="item-name" onClick={goToDetail}>{item.product_name}</div> ์ผ๋ก ์์
2) Detail
- import {useParams} from 'react-router-dom'
- let params = useParams();
- console.log('params', params.id)
- <h2>์ ํ์์ด๋๋ {params.id}</h2>