$ yarn add redux
$ yarn add react-redux // 리액트와 리덕스를 연결해주는 역할
// ./src/pages/
import { useSelector, useDispatch } from 'react-redux';
// ./src/store/index.js
import { createStore } from 'redux';
// ./src/reducer/index.js
import { combineReducers } from 'redux';
컴포넌트에서 useSelector를 사용해 store에서 특정 상태를 가져올 수 있다.
(스토어에 있는 리듀서가 반환하는 상태를 가져온다.)
컴포넌트에서 useDispatch를 사용해 dispatch를 정의하고, 이벤트 핸들러 함수에서 dispatch를 사용해 (액션 생성자로 만든) 특정 액션을 리듀서에 전달해준다.
이벤트가 발생해서 이벤트 핸들러가 실행되면 액션이 발생하고 발생한 액션은 리듀서에 전달되어 리듀서가 기존의 상태에다가 액션을 적용해 변화시킨 새로운 상태를 반환해 상태가 업데이트 된다.
react-redux를 사용하려면 반드시 App을 Provider로 감싸주어야 한다.
// ./src/index.js
import { Provider } from 'react-redux';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
useSelector
작동원리// ./src/pages/ShoppingCart.js
const state = useSelector((state) => state.itemReducer);
초기에 제공받은 코드가 위와 같이 설정되어 있었다.
useSelector
는 스토어에 있는 특정 state를 가져온다고 알고 있는데 state
를 인자로 받아온다는게 이해가 가지 않았다. state
를 전달해주는 것도 아니니 기본값이 설정되어 있을거라는 생각이 들었고, 어찌됐건 state
보다는 store
를 인자로 받아온다고 보는 것이 적합할 것 같다고 생각했다.
좀 더 확실하게 알고 싶어서 useSelector의 소스코드를 찾아봤다.
/**
* Hook factory, which creates a `useSelector` hook bound to a given context.
*
* @param {React.Context} [context=ReactReduxContext] Context passed to your `<Provider>`.
* @returns {Function} A `useSelector` hook bound to the specified context.
*/
export function createSelectorHook(context = ReactReduxContext) {
//...
}
파라미터를 설명하는 주석을 보면 인자로 받아오는 [context=ReactReduxContext]
는 <Provider>
에 넘겨준 값이라고 나온다.
// ./src/index.js
import { Provider } from 'react-redux';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
index.js에서 <Provider>
에 store
를 넘겨주고 있으므로 useSelector
의 인자로 받아오는 값은 store라고 보는 것이 맞았다.
결론: 로직상의 문제는 없지만 아래와 같이 작성하면 좀 더 직관적이고, 혼동을 줄일 수 있다.
const state = useSelector((store) => store.itemReducer);