글로버 애플리케이션 상태를 관리하기 위한 라이브러리
JS 어플리케이션에서 data-state와 UI-state를 관리해주는 도구
Redux는 "action" 이라는 이벤트를 사용하여 애플리케이션 상태를 관리하고 업데이트 하기 위한 패턴 및 라이브러리다.
단점 : 컴포넌트 갯수가 많아지거나 데이터를 교류 할 컴포넌트들이 parent-child 관계가 아니라면 복잡해진다.
redux는 flux 아키텍쳐를 좀 더 편하게 사용할 사용 할 수 있도록 해주는 라이브러리
단방향 데이터 흐름
const addTodoAction = {
//type은 string, 첫 번째 부분은 작업이 속한 기능이나 범주, 두 번째 부분은 발생한 일
type: 'todos/todoAdded',
//payload는 발생한 일에 대한 추가 정보
payload: 'Buy milk'
}
const addTodo = text => {
return {
type: 'todos/todoAdded',
payload: text
}
}
(state, action) => newState
const initialState = { value: 0 }
function counterReducer(state = initialState, action) {
// Check to see if the reducer cares about this action
if (action.type === 'counter/increment') {
// If so, make a copy of `state`
return {
...state, // value: 0
// and update the copy with the new value
value: state.value + 1
}
}
// otherwise return the existing state unchanged
return state
}
import { configureStore } from '@reduxjs/toolkit'
const store = configureStore({ reducer: counterReducer })
console.log(store.getState()) // { value: 0 }
store.dispatch({ type: 'counter/increment' }) //dispatch를 호출하여 action 객체 전달
console.log(store.getState()) // { value: 1 }
const increment = () => {
return {
type: 'counter/increment'
}
}
store.dispatch(increment())
console.log(store.getState()) // { value: 2 }
const selectCounterValue = state = state.value;
const currentValue = selectCounterValue(store.getState())
console.log(currentValue) // 2
import { useSelector } from 'react-redux'
const state = useSelector(state => state.itemReducer);
// 여기서 itemReducer는 reducer다. reducer에서 action을 전해주지 않으면 switch case문의 default에 걸리면서 기존 state를 리턴한다.
const [checkedItems, setCheckedItems] = state; //destructuring을 이용해 state를 가져올 수 있다.
import { useDispatch } from 'react-redux';
const dispatch = useDispatch();
dispatch(action객체) //dispatch안에 action객체를 담아 reducer로 전달한다.
초기 state가 있다고 치자. reducer는 전달된 action을 받고 새로운 state를 리턴한다. 이 때, 초기 state를 직접 변경하지 않고 새로운 객체를 만들어 return 한다. 이렇게 하는 이유는 위 그림과 같이 react에서는 real DOM(초기 state), virtual DOM(새로운 state)을 비교하는데 기존 state와 새로운 state의 주소값을 비교하여 다른 경우에만 새로운 state를 virtual DOM에 렌더링하여 real DOM과 비교한 뒤, 차이가 있는 부분만 부분 렌더링을 하기 때문이다.
추가적으로 기존 state를 변경하지 않음으로써 기존 상태에 대한 트랙킹을 할 수 있게 한다. (다크모드, 화이트 모드를 구현할 때)
handleClick = {handleClick}
처럼 전달해도 될 거 같은데..() => { handleClick(item) }
onClick={(e) => handleClick(e, item.id)}
이 코드는 익명함수임 handleClick에 인자를 전달하는 상황이다. 익명함수에 e와 item.id를 전달하고 익명함수안에 있는 handleClickd은 item.id를 지역 변수로 넣고 여기서 item을 가져와 쓰는거로 보면된다.<Item handleClick = {() => {
handleClick(item)
}}/>
function Item({ handleClick }) {
<button className="item-button" onClick={(e) => handleClick(e, item.id)}>장바구니 담기</button>
}
combineReducers
를 이용해 하나의 root reducer
로 합친다.import { combineReducers } from 'redux'
const rootReducer = combineReducers({
itemReducer,
notificationReducer
})
// actions creator functions
export const ADD_TO_CART = "domain/ADD_TO_CART";
export const addToCart = (itemId) => {
return {
type: ADD_TO_CART,
payload: {
quantity: 1,
itemId
}
}
}