Jane K 2022. 7. 11. 14:52

! ์˜ค๋Š˜ ํ•  ๊ฒƒ !

- ๋กœ๊ทธ์ธ ๋กœ๊ทธ์•„์›ƒ : ๋กœ๊ทธ์ธํ•˜๋ฉด ์ƒํ’ˆ๋ช… ํŽ˜์ด์ง€ ๋œจ๋„๋ก

- ์ €๋ฒˆ์— ์žฅ๋ฐ”๊ตฌ๋‹ˆ์—์„œ ์‚ญ์ œ ์ž˜ ์•ˆ๋œ๊ฑฐ ์ˆ˜์ •

- ๋ผ์šฐํŒ… ์„ค๋ช…

- ์ƒ์„ธํŽ˜์ด์ง€ ์„ค๋ช…

 

 

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>