# 243 [udemy React 완벽 가이드 노트] 리액트용 리덕스 스토어 만들기
프로젝트 폴더에
npm install
npm install redux react-redux
를 차례대로 입력한다.
redux는 react와 연동이 잘 안될 수도 있기 때문에
react-redux 서드파티 라이브러리를 같이 install해준다.
앞서 배웠던 reducer 함수와 store를 만든다.
import { createStore } from "redux";
const counterReducer = (state = { counter: 0 }, action) => {
if (action.type === "increment") {
return { counter: state.counter + 1 };
}
if (action.type === "decrement") {
return { counter: state.counter - 1 };
}
return state;
};
const store = createStore(counterReducer);
이제 리액트 앱과 리덕스 스토어를 연결해보자.
export default store;
export함으로써 다른 파일에서도 사용할 수 있게 된다.
store는 하나밖에 없다.
store를 한 번만 제공하면 된단 이야기다.
그런데 store를 제공하는 것이 무슨 의미일까?
리액트 앱에 리덕스 store 제공하기
전체 앱을 렌더하는 index.js로 간다.
리액트 애플리케이션에서 가장 높은 레벨의 파일이다.
(컴포넌트 트리의 가장 위쪽)
react-redux에서 Provider를 import한다.
App컴포넌트를 Provider 컴포넌트로 랩한다.
랩된 컴포넌트와 그 자손 컴포넌트들만이 리덕스에 접근할 수 있다.
import { Provider } from "react-redux";
컴포넌트의 대부분이 스토어에 접근하려면
지금과같이 가장 높은 레벨에서 제공해야 한다.
react-redux와 react에 어떤 스토어를 제공하고 싶은지 말하지 않고,
(store 폴더의 index.js파일이라고 말해 주지 않는다)
store를 import할 것이다.
import store from "./store/index";
그리고 Provider 컴포넌트에 store 프롭의 밸류로 import한 store를 넣어준다.
<Provider store={store}>
이 것이 리덕스 스토어를 리액트 앱에 제공하는 코드다.
이렇게 함으로써 앱컴포넌트와 다른 자식 컴포넌트는
스토어에 탭 될 수 있다.
즉, 스토어 밖으로 데이터를 가져올 수 있고, 데이터를 구독할 수 있고, 액션을 디스패치할 수도 있게 된다.
리액트 컴포넌트에서 리덕스 데이터 사용하기
이제 데이터를 App컴포넌트가 아닌 counter 컴포넌트에서 사용해보자.
Counter 컴포넌트에서 react-redux로부터 useSelector 훅을 임포트해오자.
리액트 리덕스 팀이 만든 커스텀 훅이다.
import { useSelector } from 'react-redux'
useStore 훅도 있다. 스토어에 바로 접근할 수 있는 훅이다.
하지만 useSelector가 더 편하다.
자동으로 store가 관리하는 state의 일부를 선택하게 해주기 때문이다.
그런데 클래스 기반 컴포넌트를 사용한다면
connect 함수를 wrapper로 대신 사용할 수 있다.
클래스 컴포넌트 근처에서 클래스 컴포넌트를 스토어에 연결한다.
일단 먼저 useSelector먼저 사용해 보도록 하자.
useSelector
const Counter = () => {
useSelector();
Counter 함수 안에 useSelector를 호출한다.
useSelector에는 함수를 전달한다.
전달하는 함수는 react-redux에 의해 실행될 것이며
함수가 어떤 데이터를 스토어에서 추출할지 결정할 것이다.
지금은 store의 데이터 구조는 작고 단순하지만,
더 큰 store가 되면 데이터에는 중첩되어있는 많은 객체들이 있을 것이다.
전체 state 객체에서 일부만 받아오는 작업을 할 수 있게 되는 것이다.
그러려면 useSelector에 함수를 건네줘야 한다.
함수는 리덕스가 관리하는 state를 받을 것이다.
const Counter = () => {
useSelector(state => state.counter);
추출하고 싶은 일부 state를 return 한다.
이 함수는 react-redux에 의해 실행될 것이다.
redux에 state를 보내어
이 함수로 데이터를 관리할 것이다.
이 코드를 실행해서 컴포넌트에서 필요한 state의 일부를
되돌려 받을 것이다.
그것은 counter 변수에 할당한다.
const Counter = () => {
const counter = useSelector(state => state.counter);
리덕스가 관리하는 counter다.
useSelector를 사용하면
컴포넌트를 위해서 리덕스 스토어에 react-redux가 자동으로 구독을 설정한다.
리덕스 스토어에서 데이터가 바뀔 때마다
컴포넌트가 업데이트 될 것이며
자동으로 최신 카운터를 받을 것이다.
자동으로 리덕스 스토어가 바뀌면
컴포넌트 함수가 다시 실행될 것이다.
counter는 그래서 항상 최신의 counter가 된다.
이 counter를 jsx코드에서 사용하면 된다.
action을 dispatch하여 데이터를 바꿔보자
import { useSelector, useDispatch } from "react-redux";
useDispatch hook을 import 한다
useDispatch는 Redux store에 대한 action을 보낸다.
여기서 dispatch에 전달하는 type 프로퍼티는
reducer함수에서 사용하는 식별자 중 하나여야 한다.
그리고 각각의 increment와 decrement Handler 함수를 button에 연결시켜 준다.
import { useSelector, useDispatch } from "react-redux";
import classes from "./Counter.module.css";
const Counter = () => {
const dispatch = useDispatch();
const counter = useSelector(state => state.counter);
const incrementHandler = () => {
dispatch({ type: "increment" });
};
const decrementHandler = () => {
dispatch({ type: "decrement" });
};
const toggleCounterHandler = () => {};
return (
<main className={classes.counter}>
<h1>Redux Counter</h1>
<div className={classes.value}>{counter}</div>
<div>
<button onClick={incrementHandler}>Increment</button>
<button onClick={decrementHandler}>Decrement</button>
</div>
<button onClick={toggleCounterHandler}>Toggle Counter</button>
</main>
);
};
export default Counter;
Increment나 Decrement 버튼을 누를 때마다
1씩 증가 혹은 감소한다.