App
├─ Counter Container
│ └─ Counter Component
└─ Todos Container
└─ Todos Component
const rootReducer = combineReducers({
counter,
todos
})
react-redux의 Provider로 컴포넌트 감싼다.
인자로 store 넘겨준다.
<Provider store={store}>
<App />
</Provider>
설치 : yarn add redux-devtools-extension
사용 : 스토어 생성할 때 createStore뒤에 composeWithDevTools를 인자로 설정
import { composeWithDevTools } from 'redux-devtools-extension'
const store = createStore(rootReducer, composeWithDevTools)
const CounterContainer = () => {
return <Counter />;
}
connect(mapStoreToProps, mapDispatchToProps)
mapStoreToProps : 리덕스 스토어 안의 상태를 컴포넌트의 props로 넘겨준다.
const mapStateToProps = (state) => ({
number: state.counter.number + 1,
});
mapDispatchToProps : 액션 생성 함수를 컴포넌트의 props로 넘겨준다.
const mapDispatchToProps = (dispatch) => ({
increase: () => {
dispatch(increase());
},
decrease: () => {
dispatch(decrease());
},
});
import { increase, decrease } from '../modules/counter'
number와 increase, decrease를 가져와 하위 컴포넌트에 props값으로 넘겨 줄 수 있다.
<Counter number={number} onIncrease={increase} onDecrease={decrease}>
makeContainer(연동할 컴포넌트). ( 여기선 CounterContainer )
export default connect(mapStateToProps, mapDispatchToProps)(CounterContainer);
export default connect 함수 내부에 익명함수로 설정하기. (익명함수 : mapStateToProps, mapDispatchToProps 없이)
bindActionCreators 유틸함수 사용하기
export default connect(
(state) => ({
number: state.counter.number,
}),
dispatch=>
bindActionCreators(
{
increase,
decrease,
},
dispatch
),
)(CounterContainer);
export default connect(
(state) => ({
number: state.counter.number,
}),
{
increase,
decrease,
},
)(CounterContainer);
(state) => ({
number: state.counter.number,
}),
// const {counter} = state
// == state.counter
// (state) = {counter}
({counter}) => ({
number: counter.number,
}),
설치 : yarn add redux-actions
액션 생성 함수를 간소화
export const increase = () => ({type : INCREASE})
==
export const increase = createAction(INCREASE)
리듀서의 switch/case가 아닌 handleActions 사용해 간소화
const counter = handleActions(
{
[INCREASE] : (state, action) => ({ number : state.number + 1}),
[DECREASE] : (state, action) => ({ number : state.number - 1}),
},
initialState
)
payload
export const changeInput = createAction(CHANGE_INPUT, input=>input)
export const insert = createAction(INSERT, text=> ({
id: id++,
text,
done:false,
}))
action.payload
const todo = handleActions(
{
[CHANGE_INPUT] : (state, action) => ({ ...state, input: action.payload}),
[INSERT] : (state, action) => ({
...state,
todos: state.todos.concat(action.payload)
})
}
)
const todo = handleActions(
{
[CHANGE_INPUT] : (state, {payload: input}) => ({ ...state, input}),
[INSERT] : (state, {payload: todo}) => ({
...state,
todos: state.todos.concat(todo)
})
}
)
react-redux의 useSelector Hook
connect를 안쓰고 상태 조회가 가능하다.
import {useSelector} from 'react-redux'
const number = useSelector(state => state.counter.number)
return <Counter number={number} />
react-redux의 useDispatch Hook
import {useDispatch } from 'react-redux'
const dispatch = useDispatch();
return (
<Counter
onIncrease = {() => dispatch(incrase())}
onDecrease = {() => dispatch(decrase())}
>
)
useDispatch와 useCallback은 항상 같이 쓰도록 습관화
cosnt onIncrease = useCallback(() => dispatch(increase()), [dispatch])
cosnt onDecrease = useCallback(() => dispatch(decrease()), [dispatch])
return(
<Counter onIncrease={onIncrease} onDecrease={onDecrease}>
)