리덕스를 사용하기 전엔 HOC에서 state를 관리하여 단방향으로 데이터를 넘겨줘야 했다. 이런 데이터 흐름은 불필요한 컴포넌트끼리 props로 데이터를 계속 넘겨받아야한다. 또, 넘겨받는 과정에서 props를 받는 컴포넌트도 렌더링이 되며 컴포넌트수가 많아질수록 불필요한 렌더링이 실행된다. 이러한 현상은 유지보수에도 좋지 않고 state관리에도 적절하지 않다.
리덕스를 사용하게 되면 외부 store에서 state를 관리하게 되며 props로 값을 받지 않아도 store에 접근해 값을 받아올 수 있다. 이렇게되면 불필요한 렌더링도 피할 수 있다.
전체상태를 하나의 객체에서 관리하면 페이지간 이동에도 상태가 저장된다. 하지만 모든 페이지에서 동일하게 적용되거나 저장되어야할 상태는 store에 저장하는게 좋으나 특정 페이지에서만 저장해야하는 것은 컴포넌트에서 관리하는게 낫다.
store에 접근하여 방법은 dispatch를 사용하여 값을 변경해야한다.
액션객체에는 항상 type 속성값이 존재해야하며 type으로 액션객체를 구분한다.
같은 값을 넣었을 때 같은 같이 나오는 함수만 사용해야한다. fetch, new Date, Math.random()과 같은 output이 다른 함수는 사용 불가하다.
리덕스는 Action > Middleware > reducer > store
순으로 store에 저장된다.
export const addCart = item => {
return {
type: "ADD_ITEM",
payload: item,
};
};
export const deleteCart = item => {
return {
type: "DELETE_ITEM",
payload: item,
};
};
액션은 type속성을 가진 자바스크립트 객체이며 액션 함수는 값에대한 액션(type)을 생성하는 역할을 하는 함수다.
import { useDispatch } from "react-redux";
import { addCart } from "../store/actions";
export default function ProductCard({ item }) {
const dispatch = useDispatch();
return (
<AddCartBtn onClick={() => dispatch(addCart(item))}>
);
}
상대경로에 있는 action.js에 접근하여 addCart만 import한다. dispatch는 store내장 되어있는 함수로 store에 액션객체를 전달하는 역할을 한다.
dispatch가 실행되면 reducer로 전달된다.
(state, action) => nextState
리듀서는 state(혹은 store)와 action 객체를 받고 nextstate 리턴한다.
const cartReducer = (state = INITAL_STATE, action) => {
switch (action.type) {
case "ADD_ITEM":
return [...state, action.payload];
case "DELETE_ITEM":
return [...action.payload];
default:
return state;
}
};
export default cartReducer;
const INITAL_STATE = [
{
isChecked: true,
product_name: "초기값",
},
];
디스패치가 실행된 액션객체는 reducer로 전달된다. switch문을 통해 type에 따라 값이 store에 저장된다. INITAL_STATE
는 초기값으로 store에 초기값을 줄 수 있다.
스토어는 리덕스의 상태값을 가지는 단일객체이다
import { Provider } from "react-redux";
// store가 리액트에 연동될수 있게 react-redux 라이브러리에 내장되어있는 함수다
import { createStore } from "redux";
// store를 생성하는 함수
import rootReducer from "./store/reducers";
const store = createStore(rootReducer); // store생성
ReactDOM.render(
<Provider store={store}>
<Routes />
</Provider>,
document.getElementById("root")
);
import { useSelector } from "react-redux";
const store = useSelector(store => store);
const items = useSelector(store => store.cartReducer);
console.log("store>>>", store);
console.log("items>>>", items);
useSelector는 store의 값을 확인 할 수 있는 리액트 함수이다.
onClick={() => dispatch(addCart(item))
처럼 디스패치를 통해 type을 추가해 리턴하여 리듀서로 보낸다. 데이터를 받은 리듀서는 switch문을 통해 type에 맞게 type을 빼고 store에 저장(리턴)한다.
store에 저장된 객체는 useSelector를 통해 ui에 보여질 수 있다.