import { createAction, handleActions } from 'redux-actions';
// createAction을 이용해 액션 생성 함수 설정
export const increase = createAction(INCREASE);
export const decrease = createAction(DECREASE);
// handleActions를 이용한 리듀서 함수 설정
const counter = handleActions(
{
[INCREASE]: (state, action) => ({ number: state.number + 1 }),
[DECREASE]: (state, action) => ({ number: state.number - 1 }),
},
initialState,
);
modules/todos.js
// createAction 사용해 액션 생성 함수 설정하기
export const changeInput = createAction(CHANGE_INPUT, (input) => input);
let id = 3;
export const insert = createAction(INSERT, (text) => ({
id: id++,
text,
done: false,
}));
export const toggle = createAction(TOGGLE, (id) => id);
export const remove = createAction(REMOVE, (id) => id);
// handleActions 를 이용한 리듀서 작성
const todos = handleActions(
{
[CHANGE_INPUT]: (state, action) => ({
...state,
input: action.payload,
}),
[INSERT]: (state, action) => ({
...state,
todos: state.todos.concat(action.payload),
}),
[TOGGLE]: (state, action) => ({
...state,
todos: state.todos.map((todo) =>
todo.id === action.payload ? { ...todo, done: !todo.done } : todo,
),
}),
[REMOVE]: (state, action) => ({
...state,
todos: state.todos.filter((todo) => todo.id !== action.payload),
}),
},
initialState,
);
createAction으로 만든 액션 생성 함수는 파라미터로 받아 온 값을 action.payload라는 이름으로 공통으로 넣게 된다.
따라서 기존의 업데이트 로직에서도 action.payload 값을 조회하여 업데이트
const todos = handleActions(
{
[CHANGE_INPUT]: (state, { payload: input }) => ({
...state,
input,
}),
[INSERT]: (state, { payload: todo }) => ({
...state,
todos: state.todos.concat(todo),
}),
[TOGGLE]: (state, { payload: id }) => ({
...state,
todos: state.todos.map((todo) =>
todo.id === id ? { ...todo, done: !todo.done } : todo,
),
}),
[REMOVE]: (state, { payload: id }) => ({
...state,
todos: state.todos.filter((todo) => todo.id !== id),
}),
},
initialState,
);
// immer 사용한 reducer
const todos = handleActions(
{
[CHANGE_INPUT]: (state, { payload: input }) =>
produce(state, (draft) => {
draft.input = input;
}),
[INSERT]: (state, { payload: todo }) =>
produce(state, (draft) => {
draft.todos.push(todo);
}),
[TOGGLE]: (state, { payload: id }) =>
produce(state, (draft) => {
const todo = draft.todos.find((todo) => todo.id === id);
todo.done = !todo.done;
}),
[REMOVE]: (state, { payload: id }) =>
produce(state, (draft) => {
const index = draft.todos.findIndex((todo) => todo.id === id);
draft.todos.splice(index, 1);
}),
},
initialState,
);
const 결과 = useSelector(상태 선택 함수);
const CounterContainer = () => { const number = useSelector((state) => state.counter.number); return <Counter number={number} />; };
- mapStateToProps와 같은 역할. 상태만 조회 가능하다.
컴포넌트 내부에서 스토어의 내장 함수 dispatch를 사용할 수 있게 해준다.
const dispatch = useDispatch();
return (
<Counter
number={number}
onIncrease={() => dispatch(increase())}
onDecrease={() => dispatch(decrease())}
/>
);
재사용 막기 위해 useCallback() 사용
const dispatch = useDispatch();
const onIncrease = useCallback(() => dispatch(increase()), [dispatch]);
const onDecrease = useCallback(() => dispatch(decrease()), [dispatch]);
return (
<Counter number={number} onIncrease={onIncrease} onDecrease={onDecrease} />
);
```
const TodoContainer = () => {
const { input, todos } = useSelector(({ todos }) => ({
input: todos.input,
todos: todos.todos,
}));
const dispatch = useDispatch();
const onChangeInput = useCallback((input) => dispatch(changeInput(input)), [
dispatch,
]);
const onInsert = useCallback((text) => dispatch(insert(text)), [dispatch]);
const onToggle = useCallback((id) => dispatch(toggle(id)), [dispatch]);
const onRemove = useCallback((id) => dispatch(remove(id)), [dispatch]);
return (
<Todos
input={input}
todos={todos}
onChangeInput={onChangeInput}
onInsert={onInsert}
onToggle={onToggle}
onRemove={onRemove}
/>
);
};
export default TodoContainer;
```
const store = useStore();
store dispatch({type:'SAMPLE_ACTION'})
store.getState();
export default React.memo(TodosContainer);