아래 내용들은 빠르게 Redux
를 사용하기 위해 핵심 부분만 정리해놓은 글이다. 필요한 부분만 쏙속 찾아서 보면 된다.
combineReducers
사용해서 rootReducer
만들어주기connect
함수 사용해서 컴포넌트와 리덕스 연동하기Reducer
함수 만들기const ACTIONE_NAME = "module_name/ACTION_NAME";
export const action = () => ({ type : ACTION_NAME });
or
import { createAction } from 'redux-actions'
export const action = createAction(ACTION_NAME);
파라미터가 존재하는 경우
export const action = createAction(ACTION_NAME, data => data);
// 이 작업이 필수는 아니며 생략해도 동일하게 작동
// 다만 넣어주는 것이 가독성이 좋아진다.
// 함수가 어떤 파라미터를 필요로 하는지 파악할 수 있다.
결과는 아래처럼 나온다.
{
type : ACTION_NAME,
payload : data
}
const initialState = {
number : 0
}
아래 4가지 조건 만족
function reducer(state = initialState, action) {
switch (action.type) {
case ACTION_NAME:
return {
...
};
default:
return state;
}
}
or
import { handleActions } from 'redux-actions';
(...)
const reducer = handleActions({
[ACTION_NAME] : (state, action) => ({
...
})
);
// 파라미터가 존재하는 경우
const reducer = handleActions({
[ACTION_NAME] : (state, {payload : data}) => ({
...
})
);
moduels/index.js
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
reducer1,
reducer2,
});
export default rootReducer;
src/index.js
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './modules';
const store = createStore(rootReducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
dev-tool
연결 하려면
import { composeWithDevTools } from "redux-devtools-extension";
const store = createStore(rootReducer, composeWithDevTools());
Redux
와 연동하기 위해서는 connect
함수를 사용해야 한다.
connect(mapStateToProps, mapDispatchToProps)(연동하고싶은 컴포넌트)
mapStateToProps
는 Store에 담긴 값을 받아서 Props
로 변환시켜주는 역할을, mapDispatchToProps
는 Action을 Props
에 담는 역할을 한다.
mapStateToProps
const mapStateToProps = state => ({
data: state.counter.number
});
mapDispatchToProps
import { action } from "../modules/something";
const mapDispatchToProps = dispatch => ({
action_name: () => dispatch(action())
});
or
import { bindActionCreators } from 'redux'
const mapDispatchToProps = dispatch =>
bindActionCreators(
{
action1,
action2
},
dispatch
);
Container
const SomeContainer = ({ data, action }) => {
return (
<Some number={data} onChange={action} />
);
};
export default connect(mapStateToProps, mapDispatchToProps)(SomeContainer);
useSelector
const result = useSelector(상태 선택 함수);
import {useSelector} from 'react-redux';
(...)
const SomeContainer = () => {
const data = useSelector(state => state.some.number)
return (
<Some number={data}/>
);
};
useDispatch
const dispatch = useDispatch();
import React, {useCallback} from "react";
(...)
const SomeContainer = () => {
const dispatch = useDispatch();
const onClick = useCallback(() => dispatch(click()), [dispatch]);
// 파라미터 존재하는 경우
const onChange = useCallback((input) => dispatch(change()), [dispatch]);
return (
<Some
onClick={onClick}
onChange={onChange}
/>
);
};
useAction
lib/useActions.js
import { bindActionCreators } from 'redux'
import { useDispatch } from 'react-redux'
import { useMemo } from 'react'
export function useActions(actions, deps) {
const dispatch = useDispatch()
return useMemo(
() => {
if (Array.isArray(actions)) {
return actions.map(a => bindActionCreators(a, dispatch))
}
return bindActionCreators(actions, dispatch)
},
deps ? [dispatch, ...deps] : [dispatch]
)
}
첫 번째 파라미터 : 액션 생성 함수로 이루어진 배열
두 번째 파라미터 : 이 배열 안에 원소가 바뀌면 액션 다시 디스패치
import useActions from '../lib/useActions'
(...)
const SomeContainer = () => {
const [onClick, onChange] = useActions(
[click, change],
[]
);
return (
<Some
onClick={onClick}
onChange={onChange}
/>
);
};
connect
함수의 경우 props
가 바뀔때만 렌더링을 다시 하지만 useSelector
는 아니므로 React.memo(SomeContainer)
사용해서 최적화 해주기
export default React.memo(SomeContainer);
다만 React.memo
를 항상 사용하는 것이 능사는 아니다. React.memo
를 사용해야 하는 경우는 다음과 같은 경우다.
1. 순수 함수 컴포넌트
2. 자주 렌더링을 해야하는 함수
3. 같은 props로 자주 리 렌더링 되는 함수
4. 컴포넌트가 props 비교를 필요로 하는 많은 UI 요소를 가지고 있는 경우
만약 props가 자주 변동되는 환경이라면 React.memo
를 사용한다고 해도 컴포넌트를 다시 렌더링 해야하므로 불필요한 비교 과정만 추가하는 꼴이다! 현명하게 사용하자.
잘 봤습니당 ㅎㅎ React.memo는 무조건 하는게 좋을까요? 별로 비교가 필요 없을 경우에는 memo를 하면 오히려 비교한다고 성능이 안 좋아진다고도 봤어가지구요 ㅎㅎ.