react에 redux를 연결하기 위해서는 redux, react redux가 모두 필요합니다. redux에서는 기존의 createStore()를 불러오며, react-redux에서는 Provider, useSelector(), useDispatch() 등이 주로 사용됩니다.
먼저 공유 객체를 생성해봅시다. createStore() 는 인자값으로, reducer() 함수를 받습니다. 생성 시 함께 적용해줍니다.
createStore()는 reducer 함수 외에도, 두번째 인자로 초기 state 값과, 세번째로 enhancer() 함수를 받습니다.
enhanser() 함수는 기존 redux에 기능을 덧붙히는 확장 플러그인 같은 거라고 생각하시면 됩니다. 주로 dispatch와 reducer 사이에 비동기 로직을 사용하는 thunk 나 saga를 통해 middleware 기능을 추가하는 용도로 주로 쓰이는 듯 합니다.
reducer()는 2개의 인자를 받습니다. 하나는 현재의 state 값이고 두번째는 state를 변경시키는 액션 객체 입니다.
import {creaetStore} from "redux";
function reducer(currentState, action) {
if (currentState === undefined) {
return {
number: 1,
};
}
// 불변성 방지
const newState = { ...currentState };
if (action.type === "PLUS") {
newState.number++;
}
return newState;
}
const store = createStore(reducer);
Provider는 여기 컴포넌트 부터 공유 데이터에 접근하게 하겠어! 라는 확인 선언 같은 것입니다. Provider 컴포넌트에 래핑된 컴포넌트 부터 모든 자식 컴포넌트까지 공유 데이터 객체에 접근이 가능합니다.
Provider는 store라는 속성 값을 지닐 수 있습니다. 여기에 createStore() 함수 값을 함께 넣어주면, 이후 해당 공유 객체로 접근하는게 가능해집니다.
보통 어디에서나 접근이 가능하도록 App() 컴포넌트에 적용시키는 듯 합니다.
const App = () => {
return (
<div className={classes.container}>
<Provider store={store}>
<h1>Root</h1>
<Left1></Left1>
<Right1></Right1>
</Provider>
</div>
);
};
export default App;
querySelector를 아직 기억하시나요? 전체의 HTML 가운데 하나의 태그 정보를 불러오는 함수 였습니다. useSelector도 이와 비슷합니다. 현재 공유 객체 가운데 필요한 데이터만 추출하여, 렌더링하는 것이 가능합니다.
const store = createStore(reducer);
const App = () => {
return (
<div className={classes.container}>
<Provider store={store}>
<h1>Root</h1>
<Left1></Left1>
<Right1></Right1>
</Provider>
</div>
);
};
export default App;
const Left1 = (props) => {
console.log(1);
return (
<div>
<h1>Left1</h1>
<Left2></Left2>
</div>
);
};
const Left2 = (props) => {
console.log(2);
return (
<div>
<h1>Left2</h1>
<Left3></Left3>
</div>
);
};
const Left3 = (props) => {
console.log(3);
const number = useSelector(({ number }) => number);
return (
<div>
<h1>Left3 - {number}</h1>
</div>
);
};
useDispatch()는 공유 객체에 액션을 전달하여, 이제 데이터를 바꿀 겁니다라고 요청하는 함수입니다.
function reducer(currentState, action) {
if (currentState === undefined) {
return {
number: 1,
};
}
const newState = { ...currentState };
if (action.type === "PLUS") {
newState.number++;
}
return newState;
}
const store = createStore(reducer);
현재 store의 reducer에는 action.type이 "PLUS" 인 경우 데이터를 변경하는 조건문을 가지고 있습니다. 이를 실행하는 dispatch() 함수를 보내겠습니다.
const Right3 = (props) => {
const dispatch = useDispatch();
return (
<div>
<h1>Right3</h1>
<button
onClick={() => {
// 타입이 플러스인 객체를 reducer의 action 객체로 보냅니다.
dispatch({ type: "PLUS" });
}}
>
number up!
</button>
</div>
);
};