๐โ๏ธ ์ฅ๋ฐ๊ตฌ๋ ํ์ด์ง ๋ง๋ค๊ธฐ
// Cart.js
import { Table } from 'react-bootstrap'
let state = useSelector((state)=> state)
<Table>
<thead>
<tr>
<th>#</th>
<th>์ํ๋ช
</th>
<th>์๋</th>
<th>๋ณ๊ฒฝํ๊ธฐ</th>
</tr>
</thead>
<tbody>
{
state.cart.map((a, i)=>
<tr key={i}>
<td>1</td>
<td>{state.cart[i].name}</td>
<td>{state.cart[i].count}</td>
<td>์๋
</td>
</tr>
)
}
</tbody>
</Table>
โ๏ธ Redux
โ๏ธ Redux ์ฐ๋ฉด ์ข์ ์
- props ์์ด ํธ๋ฆฌํ๊ฒ state ๊ณต์ ํ ์ ์๊ฒ ๋์์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
! ๊ฐ๋จํ ๊ฑฐ ๋ง๋ค ๋, ์ปดํฌ๋ํธ๊ฐ ๋ช ๊ฐ ์์ ๋ → props ์ฐ๋๊ฒ ๋ ์ด๋์
- ์ด๊ฑฐ ์ค์นํ๋ฉด js ํ์ผ ํ๋์ state๋ค์ ๋ณด๊ดํ ์ ์๋๋ฐ, ๊ทธ๊ฑธ ๋ชจ๋ ์ปดํฌ๋ํธ๊ฐ ์ง์ ๊บผ๋ด์ธ ์ ์์.
- ๊ทธ๋์ ๊ท์ฐฎ์ props ์ ์ก์ด ํ์ํ์ง ์๋ค.
โ๏ธ Redux ์ค์น
npm install @reduxjs/toolkit react-redux
- redux toolkit์ redux์ ๊ฐ์ ๋ฒ์ (๋ฌธ๋ฒ์ด ์ข ๋ ์ฌ์์ง๋ค)
- package.json์์ "react", "react-dom" ๋ฒ์ ์ด 18.1.x ์ด์์ด๋ฉด ์ฌ์ฉ๊ฐ๋ฅ(์๋ ์ง์ ์์ ํ๋ฉด ํ์ผ ์ ์ฅํ๊ณ ํฐ๋ฏธ๋์์ npm install ๋๋ฌ๋ ๋จ)
โ๏ธ Redux ์
ํ
import { configureStore } from '@reduxjs/toolkit'
export default configureStore({
reducer: { }
})
1. ์๋ฌด๋ฐ๋ store.js ํ์ผ์ ๋ง๋ค์ด์ ์ ์ฝ๋๋ฅผ ๋ณต๋ถํด์ค๋ค. (state๋ค์ ๋ณด๊ดํ๋ ํ์ผ)
import { Provider } from "react-redux";
import store from './store.js'
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
</React.StrictMode>
);
2. index.js ํ์ผ ๊ฐ์ Provider ๋ผ๋ ์ปดํฌ๋ํธ์ ์๊น ์์ฑํ ํ์ผ์ import ํด์จ๋ค. ๊ทธ๋ฆฌ๊ณ ๋ฐ์ <Provider store={import ํด์จ๊ฑฐ} ์ด๊ฑธ๋ก <App/>์ ๊ฐ์ธ๋ฉด ๋๋ค.
โ๏ธ Redux store์ state ๋ณด๊ดํ๋ ๋ฒ
- store.js ํ์ผ์ ์ด์ด์ ์ด๋ ๊ฒ ์ฝ๋์ง๋ฉด state ํ๋ ๋ง๋ค ์ ์๋ค.
step 1. createSlice()๋ก state ๋ง๋ค๊ณ
step 2. configureStore() ์์ ๋ฑ๋ก
import { configureStore, createSlice } from '@reduxjs/toolkit'
let user = createSlice({
name : 'user',
initialState : 'kim'
})
export default configureStore({
reducer: {
user : user.reducer
}
})
1. createSlice() ์๋จ์์ import ํด์จ ๋ค์์ { name : 'state์ด๋ฆ', initialState : 'state๊ฐ' } ์ด๊ฑฐ ๋ฃ์ผ๋ฉด state ํ๋ ์์ฑ๊ฐ๋ฅ(createSlice( ) ๋ useState( ) ์ ์ฉ๋๊ฐ ๋น์ทํ๋ค๊ณ ๋ณด๋ฉด ๋๋ค.)
2. state ๋ฑ๋ก์ configureStore( ) ์์ ํ๋ฉด ๋๋ค. { ์๋ช
: createSlice๋ง๋ ๊ฑฐ.reducer } ์ด๋ฌ๋ฉด ๋ฑ๋ก ๋. ์ฌ๊ธฐ ๋ฑ๋กํ state๋ ๋ชจ๋ ์ปดํฌ๋ํธ๊ฐ ์์ ๋กญ๊ฒ ์ฌ์ฉ๊ฐ๋ฅ.
โ๏ธ Redux store์ ์๋ state ๊ฐ์ ธ๋ค์ฐ๋ ๋ฒ
// Cart.js
import { useSelector } from "react-redux"
function Cart(){
let a = useSelector((state) => { return state } )
// let a = useSelector((state) => state.user ) ์ด๋ ๊ฒ ํ๋ฉด ๋ ํธ๋ฆฌํ ์๋?! ํธํ ๊ฑธ๋ก ใฑใฑ
console.log(a)
return (์๋ต)
}
- ์๋ฌด ์ปดํฌ๋ํธ์์ useSelector((state) => { return state } ) ์ฐ๋ฉด store์ ์๋ ๋ชจ๋ state๊ฐ ๊ทธ ์๋ฆฌ์ ๋จ๋๋ค. ({ user : 'kim' } ์ด๋ฐ๊ฑฐ ์ถ๋ ฅ๋ ๋ฏ)
โ๏ธ store์ state ๋ณ๊ฒฝํ๋ ๋ฒ
- state ์์ ํด์ฃผ๋ ํจ์๋ถํฐ store.js์ ๋ง๋ค์ด๋๊ณ ๊ทธ๊ฑธ ์ปดํฌ๋ํธ์์ ์ํ ๋ ์คํํ๋ ์์ผ๋ก ์ฝ๋๋ฅผ ์ง ๋ค.
1. store.js ์์ state ์์ ํด์ฃผ๋ ํจ์๋ถํฐ ๋ง๋ ๋ค
let user = createSlice({ // ํจ์ ์๋ช
์์ ๋กญ๊ฒ
name : 'user', // ํ๋ผ๋ฏธํฐ ํ๋ ์๋ช
ํ๋ฉด ๊ทธ๊ฑด ๊ธฐ์กด์ state๊ฐ ๋๋ค
initialState : 'kim',
reducers : {
changeName(state){
return 'john ' + state // return ์ฐ์ธก์ ์๋ก์ด state ์
๋ ฅํ๋ฉด ๊ทธ๊ฑธ๋ก ๊ธฐ์กด state๋ฅผ ๊ฐ์์น์
}
}
})
// ์ด์ changeName() ์ธ ๋๋ง๋ค 'kim' -> 'john kim' ์ด๋ ๊ฒ ๋ณํจ
- slice ์์ reducers : { } ์ด๊ณ ๊ฑฐ๊ธฐ ์์ ํจ์ ๋ง๋ค๋ฉด ๋๋ค.
2. ๋ค๋ฅธ ๊ณณ์์ ์ฐ๊ธฐ ์ข๊ฒ export ํด๋๊ธฐ
export let { changeName } = user.actions
- ์ด๋ฐ ์ฝ๋๋ฅผ store.js ๋ฐ์ ์ถ๊ฐ
- slice์ด๋ฆ.actions ๋ผ๊ณ ์ ์ผ๋ฉด state ๋ณ๊ฒฝํจ์๊ฐ ์ ๋ถ ๊ทธ ์๋ฆฌ์ ์ถ๋ ฅ๋จ
- ๊ทธ๊ฑธ ๋ณ์์ ์ ์ฅํ๋ค๊ฐ export ํ๋ผ๋ ๋ป์ผ ๋ฟ
3. ์ํ ๋ import ํด์ ์ฌ์ฉ, ๊ทผ๋ฐ dispatch()๋ก ๊ฐ์ธ์ ์จ์ผํจ
- ์๋ฅผ ๋ค์ด Cart.js ์์ ๋ฒํผ๊ฐ์๊ฑฐ ํ๋ ๋ง๋ค๊ณ ๊ทธ ๋ฒํผ ๋๋ฅด๋ฉด state๋ฅผ 'kim' -> 'john kim' ์ผ๋ก ๋ณ๊ฒฝํ๊ณ ์ถ์ผ๋ฉด
// Cart.js
import { useDispatch, useSelector } from "react-redux" //useDispatch ๋ผ๋ ๊ฒ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๊ฐ์ ธ์ค๊ณ
import { changeName } from "./../store.js" // store.js์์ ์ํ๋ state๋ณ๊ฒฝํจ์ ๊ฐ์ ธ์ค๊ณ
(์๋ต)
<button onClick={()=>{
dispatch(changeName()) //dispatch( state๋ณ๊ฒฝํจ์() ) ์ด๋ ๊ฒ ๊ฐ์ธ์ ์คํํ๋ฉด state ์ง์ง๋ก ๋ณ๊ฒฝ
}}>๋ฒํผ์</button>
- ์ด๋ ๊ฒ ์ฝ๋ ์ง๋ฉด ๋๋ค.
๐ค ๋ณต์กํ ๊ฒ ๊ฐ์๋ฐ์?
store ์์ ์๋ state ์์ ํ๊ณ ์ถ์ผ๋ฉด
- state ์์ ํด์ฃผ๋ ํจ์๋ฅผ store.js์ ๋ง๋ค์ด๋๊ณ
- ์ปดํฌ๋ํธ๋ ๊ทธ๊ฑธ ๋ถ๋ฅด๊ธฐ๋ง ํ๋ ์์ผ๋ก state ์์ ํ๊ฒ ๋์ด์์
! ์ปดํฌ๋ํธ์์ state ์ง์ ์์ ํ๋ฉด ํธํ์ง ์๋
- ๋น์ฅ์ ํธํ ์ง ๋ชฐ๋ผ๋ ๋์ค์ ํ๋ก์ ํธ๊ฐ ์ปค์ง๋ฉด ์ฌ๊ฐํ ๋จ์ ์ด ์์ ์ ์๋ค.
- ์ปดํฌ๋ํธ 100๊ฐ์์ ์ง์ 'kim' ์ด๋ผ๋ state ๋ณ๊ฒฝํ๋ค๊ฐ ๊ฐ์๊ธฐ 'kim'์ด 123์ด ๋์ด๋ฒ๋ฆฌ๋ ๋ฒ๊ทธ๊ฐ ๋ฐ์ํ๋ฉด ๋ฒ์ธ ์ฐพ์ผ๋ ค๊ณ ์ปดํฌ๋ํธ 100๊ฐ๋ฅผ ๋ค ๋ค์ ธ์ผํ๋ค.
- ๊ทผ๋ฐ state ์์ ํจ์๋ฅผ store.js์ ๋ฏธ๋ฆฌ ๋ง๋ค์ด๋๊ณ ์ปดํฌ๋ํธ๋ ๊ทธ๊ฑฐ ์คํํด๋ฌ๋ผ๊ณ ๋ถํ๋ง ํ๋ ์์ผ๋ก ์ฝ๋๋ฅผ ์ง๋์ผ๋ฉด 'kim'์ด 123์ด ๋์ด๋ฒ๋ฆฌ๋ ๋ฒ๊ทธ๊ฐ ๋ฐ์ํ์ ๋ ๋ฒ์ธ์ฐพ๊ธฐ๊ฐ ์์ํ๋ค. ๋ฒ์ธ์ ๋ฌด์กฐ๊ฑด store.js์ ์๊ธฐ ๋๋ฌธ! (์์ ํจ์๋ฅผ ์ ๋ง๋ค์ด๋จ๋ค๋ฉด)
โ๏ธ redux state๊ฐ array/object์ธ ๊ฒฝ์ฐ ๋ณ๊ฒฝํ๋ ค๋ฉด
- ๋์ถฉ {name : 'kim', age : 20} ์ด๋ ๊ฒ ์๊ธด ์๋ฃ๋ฅผ state๋ก ๋ง๋ค์ด๋ณด์
- ๊ทผ๋ฐ ์ ๊ธฐ์ 'kim' -> 'park' ์ด๋ ๊ฒ ๋ณ๊ฒฝํ๊ณ ์ถ์ผ๋ฉด state ๋ณ๊ฒฝํจ์ ์ด๋ป๊ฒ ๋ง๋ค์ด์ผํ ๊น
let user = createSlice({
name : 'user',
initialState : {name : 'kim', age : 20},
reducers : {
changeName(state){
return {name : 'park', age : 20}
}
}
})
- ์ด๋ ๊ฒ ์ฐ๋ฉด return ์ค๋ฅธ์ชฝ์ ์ ์๊ฑธ๋ก ๊ธฐ์กด state๋ฅผ ๋ณ๊ฒฝ์ํค๋ ๊ผด์ด๊ธฐ ๋๋ฌธ์ ๋น์ฐํ changeName() ์ฌ์ฉ์ ๋ณ๊ฒฝ๋๋ค.
let user = createSlice({
name : 'user',
initialState : {name : 'kim', age : 20},
reducers : {
changeName(state){
state.name = 'park'
}
}
})
- ๊ทผ๋ฐ state๋ฅผ ์ง์ ์์ ํ๋ผ๊ณ ํด๋ ๋ณ๊ฒฝ ์ ๋๋ค.
- ๊ทธ ์ด์ ๋ mmer.js ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ state ์ฌ๋ณธ์ ํ๋ ๋ ์์ฑํด์ค ๋๋ถ์ธ๋ฐ Redux ์ค์นํ๋ฉด ๋ธ๋ ค์์ ๊ทธ๋ ๋ค.
- ๊ทธ๋์ ๊ฒฐ๋ก ์ array/object ์๋ฃ์ ๊ฒฝ์ฐ state๋ณ๊ฒฝ์ state๋ฅผ ์ง์ ์์ ํด๋ฒ๋ ค๋ ์ ๋๋๊น ์ง์ ์์ ํ๋ผ!
- ์ฐธ๊ณ ) ๊ทธ๋์ state ๋ง๋ค ๋ ๋ฌธ์๋ ์ซ์ํ๋๋ง ํ์ํด๋ redux์์ ์ผ๋ถ๋ฌ object ์๋๋ฉด array์ ๋ด๋ ๊ฒฝ์ฐ๋ ์๋ค. ์์ ์ด ํธ๋ฆฌํด์ง๊ธฐ ๋๋ฌธ
โ๏ธ state ๋ณ๊ฒฝํจ์๊ฐ ์ฌ๋ฌ๊ฐ ํ์ํ๋ฉด
- ๋ฒํผ์ ๋๋ ์ ๋ age๊ฐ +10, +100 ์ฉ ์ฆ๊ฐํ๊ธธ ์ํ ๋, +10 ํ๋ ํจ์ ๋ง๋ค๊ณ +100 ํ๋ ํจ์ ๋ง๋ค ํ์ X → ํ๋ผ๋ฏธํฐ๋ฌธ๋ฒ ์ด์ฉ
let user = createSlice({
name : 'user',
initialState : {name : 'kim', age : 20},
reducers : {
increase(state, a){ // increase(10) ํ๋ฉด +10, increase(100) ํ๋ฉด +100
state.age += a.payload
}
}
})
๐โ๏ธ ์๋ +1 ๊ธฐ๋ฅ ๋ง๋ค๊ธฐ
let cart = createSlice({
name : 'cart',
initialState : [
{id : 0, name : 'White and Black', count : 2},
{id : 2, name : 'Grey Yordan', count : 1}
],
reducers : {
addCount(state, action){
let ๋ฒํธ = state.findIndex((a)=>{ return a.id === action.payload }) // findIndex() ์ฌ์ฉํด์ ๊ฐ์ id ๊ฐ์ง ์ํ ์ฐพ์์ +1
state[๋ฒํธ].count++
}
}
})
// Cart.js
import { createSlice } from '@reduxjs/toolkit'
<tbody>
{
state.cart.map((a, i)=>
<tr key={i}>
<td>{state.cart[i].id}</td>
<td>{state.cart[i].name}</td>
<td>{state.cart[i].count}</td>
<td>
<button onClick={()=>{ dispatch(addCount(state.cart[i].id)) }}>+</button> <!-- ๋ฒํผ ๋๋ฅด๋ฉด ์์ ์๋ ์ํ id๋ฅผ payload๋ก ์ ์ก -->
<!-- ๋ฒํผ ๋๋ฅด๋ฉด ๋ฒํผ ์์ ์๋ ์ํ id ๊ฐ์ ธ์์ ์ด๊ฑฐ๋ ๋๊ฐ์ id๋ฅผ ๊ฐ์ง ์ํ์ state์์ ์ฐพ์์ ๊ทธ๊ฑธ +1 -->
</td>
</tr>
)
}
</tbody>
๐โ๏ธ ์ฃผ๋ฌธ ๋ฒํผ ๋๋ฅด๋ฉด ์ฅ๋ฐ๊ตฌ๋ state์ ์๋ก์ด ์ํ ์ถ๊ฐ
let cart = createSlice({
name : 'cart',
initialState : [
{id : 0, name : 'White and Black', count : 2},
{id : 2, name : 'Grey Yordan', count : 1}
],
reducers : {
addCount(state, action){
state[action.payload].count++
},
addItem(state, action){ // addItem( {id : 2, name : 'Grey Yordan', count : 1} ) ์ด๋ ๊ฒ ์ฌ์ฉํ๋ฉด{id : 2, name : 'Grey Yordan', count : 1} ์ด ์ํ์ด state์ ์ถ๊ฐ
state.push(action.payload)
}
}
})
// Detail.js
import { createSlice } from '@reduxjs/toolkit'
<div className="col-md-6">
<h4 className="pt-5">{์ฐพ์์ํ.title}</h4>
<p>{์ฐพ์์ํ.content}</p>
<p>{์ฐพ์์ํ.price}์</p>
<button className="btn btn-danger" onClick={()=>{
dispatch(addItem( {id : 1, name : 'Red Knit', count : 1} ))
}}>์ฃผ๋ฌธํ๊ธฐ</button>
</div>
</div>
๋ณธ ํฌ์คํ ์ << React ๋ฆฌ์กํธ ๊ธฐ์ด๋ถํฐ ์ผํ๋ชฐ ํ๋ก์ ํธ๊น์ง! >> ๊ฐ์๋ฅผ ์ฐธ๊ณ ํฉ๋๋ค.