트리구조로 내려오는 컴포넌트 -> 값을 변경하려면 state -> 값 전달 props(단방향, 위에서 아래로) => 비효율적임
1-2-3-4-5-6-7 와 같은 순차적인 계층구조가 아닌
1 —store—> 7 스토어를 통해 값을 전달
컴포넌트 ——dispatch()——> 액션(객체) ---> 리듀서 ---> 스토어 --connect()——> 컴포넌트
중앙 통제실과 같은 역할.
프로젝트에 리덕스를 적용한다.
데이터가 새로운 값으로 변경, 갱신 되면 connect 함수(또는 UseSelector)를 통해 컴포넌트에 전달
구성 : 현재 앱의 State , Reducer, 내장함수
State를 수시로 확인, 현재 변경된 상태를 알려 준다. (참고: 자체가 변경되는 것이 아닌 새로운 값이 덧붙여지는 형태임)
Store 내장 함수 (1) Dispatch() : reducer한테 액션을 실행하라고 시키는 함수(리듀서에게 액션을 전달. (전달자))
Store 내장 함수 (2) Subscribe() 구독 : store를 주시하고 있다가 액션이 디스패치될 때마다 함수를 호출
<스토어 사용 규칙>
- 하나의 프로젝트에 하나의 스토어만 사용
- state는 읽기 전용. 고유값은 수정되지 않음
- 리듀서는 현재상태의 state 객체 자체를 수정하는 것이 아니고 변화를 일으킨 새로운 상태 객체를 만들어서 반환
💡 액션 타입, 액션 생성 함수, 리듀서 코드를 작성해야 한다!
🗂 src>store>actions>index.js
export const addCart = (item) => {
return{
type : "ADD_ITEM",
payload : item//type 외의 나머지값
}
}//액션 생성 함수
🗂 src>store>reducers>cartReducer.js
const cartReducer = (state = [], action) => {
switch(action.type){
case "ADD_ITEM"://action의 타입이 ADD_ITEM이면
return[...state, action.payload];//return 값이 있으면 break문 안 써도 됨
case "DELETE_ITEM"://action의 타입이 DELETE_ITEM이면
return[...action.payload];//새로 수정되는 것이 아니라 갖고있던 값만 뱉어냄
default:
return state;
}
}
export default cartReducer;
🗂 src>index.js
import { createStore } from 'redux';
import rootReducer from "./store/reducers/"
import { Provider } from 'react-redux';
const store= createStore(rootReducer);
ReactDOM.render(
<React.StrictMode>
<Provider store= { store }>//💡props로 store를 전달해줘야함!
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
(1) react-redux의 UseDispatch 훅 사용
-> 컴포넌트 내부에서 스토어의 내장함수인 dispatch를 사용할 수 있게 함
🗂 src>components>ProductItem.js
import React from "react";
import './ProductItem.css';
import { useDispatch } from 'react-redux';
import { addCart } from "../store/actions";
function ProductItem ({ item }){
const dispatch = useDispatch();
return(
<div className="ProductItem">
<img className="item-image" src={item.product_img} alt="product-image" />
<div className="item-name"> {item.product_name}</div>
<div className="item-price">₩{item.price}</div>
<button className="add-cart-btn" onClick={()=> dispatch(addCart(item))}>
<i class="fas fa-plus"></i>
Add to Cart
</button>
</div>
)
}
export default ProductItem;
(2) react-redux의 UseSelector 훅 사용
-> connect 함수 사용하지 않고 리덕스의 상태 조회
🗂src>components>ProductItem.js
import { useSelector } from "react-redux";
function Nav (){
const navi = useNavigate();
const cart = useSelector(store => store.cartReducer);
const cartNum = cart.length;
return(
<nav className="Nav">
<h1 className="nav-title"><Link to="/">HnM</Link></h1>{/* 링크연결 1) Link 컴포넌트 사용 */}
<i className="fas fa-shopping-cart" onClick={()=> navi("/cart")}>{/* 링크연결 2) 라우터 버전6, navigate 컴포넌트 사용 */}
<span className="cart-amount">{ cartNum }</span>
</i>
</nav>
)
}
export default Nav