redux toolkit
: 더 간략하게 리덕스를 사용할 수 있다!
yarn add @reduxjs/toolkit
createAction()을 사용해 action을 만들어보자!
store.js에 createAction을 import 해오자
import { createAction } from '@reduxjs/toolkit';
store.js의 addToDo와 deleteToDo를 createAction을 사용해 교체해보자!
/* 기존 redux 코드
const ADD = 'ADD';
const DELETE = 'DELETE';
const addToDo = (text) => {
return {
type: ADD,
text
};
};
const deleteToDo = (id) => {
return {
type: DELETE,
id: parseInt(id)
};
};
*/
const addToDo = createAction('ADD');
const deleteToDo = createAction('DELETE');
reducer의 switch문에 더이상 ADD, DELETE 변수가 존재하지 않는다! 교체해보자!
const reducer = (state = [], action) => {
switch (action.type) {
case addToDo.type:
return [{ text: action.payload, id: Date.now() }, ...state];
case deleteToDo.type:
return state.filter((toDo) => toDo.id !== action.payload);
default:
return state;
}
};
ToDo.js를 수정하자
function ToDo({ text, onBtnClick, id }) {
return (
<li>
<Link to={`/${id}`}>{text}</Link>
<button onClick={onBtnClick}>DEL</button>
</li>
);
}
createReducer()를 사용해 reducer의 코드를 간략화해보자!
/* 기존 reducer 코드
const reducer = (state = [], action) => {
switch (action.type) {
case addToDo.type:
return [{ text: action.payload, id: Date.now() }, ...state];
case deleteToDo.type:
return state.filter((toDo) => toDo.id !== action.payload);
default:
return state;
}
};
*/
const reducer = createReducer([], {
[addToDo]: (state, action) => {
// push()는 state를 mutate해준다. return X
state.push({ text: action.payload, id: Date.now() });
},
// filter()는 state가 mutate되지 않고, 새로운 배열을 return 한다.
[deleteToDo]: (state, action) => state.filter((toDo) => toDo.id !== action.payload)
});
configureStore()을 사용한 사이트는 Redux DevTool를 사용해 state들을 볼 수 있다!
createSlice()를 사용해 한번 더 코드를 간략화하자
store.js에 createSlice()로 교체하자
import { createStore } from 'redux';
import { configureStore, createSlice } from '@reduxjs/toolkit';
/*
const addToDo = createAction('ADD');
const deleteToDo = createAction('DELETE');
*/
/*
const reducer = (state = [], action) => {
switch (action.type) {
case addToDo.type:
return [{ text: action.payload, id: Date.now() }, ...state];
case deleteToDo.type:
return state.filter((toDo) => toDo.id !== action.payload);
default:
return state;
}
};
*/
/*
const reducer = createReducer([], {
[addToDo]: (state, action) => {
state.push({ text: action.payload, id: Date.now() });
},
[deleteToDo]: (state, action) => state.filter((toDo) => toDo.id !== action.payload)
});
*/
const toDos = createSlice({
name: 'toDosReducer',
initialState: [],
reducers: {
add: (state, action) => {
state.push({ text: action.payload, id: Date.now() });
},
remove: (state, action) => state.filter((toDo) => toDo.id !== action.payload)
}
});
export const { add, remove } = toDos.actions;
export default configureStore({ reducer: toDos.reducer });
Home.js 수정
import React, { useState } from 'react';
import { connect } from 'react-redux';
import { add } from '../store';
import ToDo from '../components/ToDo';
function Home({ toDos, addToDo }) {
const [text, setText] = useState('');
function onChange(e) {
setText(e.target.value);
}
function onSubmit(e) {
e.preventDefault();
addToDo(text);
setText('');
}
return (
<>
<h1>To Do</h1>
<form onSubmit={onSubmit}>
<input type='text' value={text} onChange={onChange} />
<button>Add</button>
</form>
<ul>
{toDos.map((toDo) => (
<ToDo {...toDo} key={toDo.id} />
))}
</ul>
</>
);
}
function mapStateToProps(state) {
return { toDos: state };
}
function mapDispatchToProps(dispatch) {
return {
addToDo: (text) => {
dispatch(add(text));
}
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Home);
ToDos.js
import React from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { remove } from '../store';
function ToDo({ text, onBtnClick, id }) {
return (
<li>
<Link to={`/${id}`}>{text}</Link>
<button onClick={onBtnClick}>DEL</button>
</li>
);
}
function mapDispatchToProps(dispatch, ownProps) {
return {
onBtnClick: () => dispatch(remove(ownProps.id))
};
}
export default connect(null, mapDispatchToProps)(ToDo);