일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- BIND
- 컴포넌트
- CSS
- function
- todolist
- ES6
- js
- redux
- this
- 객체
- 리액트
- const
- 함수
- var
- typescript
- 모던 자바스크립트
- 모던
- 뷰
- 타입스크립트
- VUE
- null
- let
- Interface
- 투두리스트
- 라우터
- 데이터 타입
- Number
- 자바스크립트
- react
- 스코프
- Today
- Total
홍준혁
React X Redux 투두리스트 예제 본문
리액트에서 리덕스 구조를 이해하려면 투두 리스트만큼 가성비 좋은 게 없다.
그럼 간단히 리액트에서 투두리스트를 리덕스로 구현해보자.
먼저 src의 구조는
이렇게 크게 세가지로 나뉜다.
modules는 액션 타입 , 액션 생성 함수 , 리듀서를 한 파일에서 관리하는 Ducks패턴을 모아놓은 디렉터리라고 생각하자.
즉, 기존에는 액션 타입 , 액션 생성 함수 , 리듀서이 세 가지를 각각 다른 파일에 나눠서 개발했다면 Ducks패턴은 그걸 짬뽕시켜놓은 개념이다.
Ducks 패턴의 장점은 새로운 액션을 만들때 번거로운 작업을 하지 않아도 된다.
이제 component에서 간단히 input , button , ul만 태그 해놓자.
<>
<input type="text"/>
<button>제출</button>
<ul></ul>
</>
그다음에 modules폴더에 todos.js라는 파일을 만들어서 액션 타입 , 액션 생성 함수 , 리듀서를 정의해보자.
먼저 액션 타입.
//액션 타입 정의
const INSERT = 'todos/INSERT'; //새로운 todo를 등록함
const TOGGLE = 'todos/TOGGLE'; //done 상태를 체크함
const REMOVE = 'todos/REMOVE'; //todo를 삭제함
이렇게 constants에 액션 타입을 저장해놓은 이유는 변수로 지정했을 때, 오타가 난 것을 바로 알 수 있기 때문이다.
이제 액션 생성 함수를 정의할 건데, 이는 객체를 만들어준다고 이해하자.
//액션 생성 함수 만들기
//전달받은 파라미터는 액션 객체 안에 추가필드로 들어감
let id = 1; //todo가 추가될때마다 id값이 증가함.
//각 todo마다 유니크한 값을 부여하기 위함
export const insert = (text) => ({
type: INSERT,
todo: {
id: id++,
text,
done: false,
},
});
export const toggle = (id) => ({
type: TOGGLE,
id,
});
export const remove = (id) => ({
type: REMOVE,
id,
});
보다시피, 액션 함수가 실행되면 하나의 객체를 반환하는 모습을 볼 수 있다.
그다음에는 리듀서를 정의해보자.
//초기 state 및 리듀서 정의
const initialState = {
todos: [],
};
function todos(state = initialState, action) {
switch (action.type) {
case INSERT:
return {
...state,
todos: state.todos.concat(action.todo),
};
case TOGGLE:
return {
...state,
todos: state.todos.map((todo) =>
todo.id === action.id ? { ...todo, done: !todo.done } : todo
),
};
case REMOVE:
return {
...state,
todos: state.todos.filter((todo) => todo.id !== action.id),
};
default:
return state;
}
}
각 액션 타입별로 할 일을 구분해주는 것이 리듀서의 역할이다.
todos리듀서는 state와 action을 받는데, state는 변하기 전의 상태를 의미하고 action은 액션 함수를 의미한다.
그렇게 한 다음에 만든 리듀서를 꼭
export default todos
라고 해주자.
이제 리덕스 파일은 거의 다 만들었다고 봐도 무방하다.
src에 있는 index.js에 가서
import { createStore } from 'redux';
import { Provider } from 'react-redux';
이 두 개를 불러와주는데,
createStore는 아까 만들어준 리듀서를 파라미터로 받아서 스토어로 만들어주는 함수이다.
Provider는 공급자인데, 프로바이더 하위에 store를 뿌려주는 역할을 한다.
const store = createStore(reducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
이렇게 해주면 App포함 하위에 있는 컴포넌트는 store를 불러 쓸 수 있다.
참고로 reducer는 아까 만들어준 리듀서를 불러와주면 된다.
import reducer from './modules/todos';
참고로 modules의 파일들이 복수개가 될 수 있는데 그럴 때는 combineReducers라는 함수를 redux에서 불러와서 병합해주면 된다.
modules에 index.js를 만들고
import { combineReducers } from 'redux';
import counter from './counter';
import todos from './todos';
const rootReducer = combineReducers({
counter,
todos,
});
export default rootReducer;
요런 식으로 해주면 된다.
이제 컨테이너에서 프로바이더가 공급해준 store를 가져올 타이밍이다.
const { todos } = useSelector((state) => ({
todos: state.todos,
}));
useSelector라는 함수를 사용해서 state를 가져왔다.
이게 useSelector라는 것이 Hooks인데 이 Hooks를 안 쓴다면 connect라는 걸 써서
connect( mapStateToProps, mapDispatchToProps )(Counter);
이렇게 해주어야 한다.
여기서 connect는... 쓸 일이 잘 없을 거 같다. 왜냐하면 useSelector가 너무 편하기 때문이다.
쨋튼 state를 가져왔으면 이제 todos 배열을 map을 해주자.
const todosMap = todos.map((todo) => (
<li key={todo.id}>
{todo.text}
<button>삭제</button>
</li>
));
이런 식으로 작성하고 이 todosMap이라는 배열을 컴포넌트로 넘겨줘서 {todosMap}이렇게 해주기만 하면 배열 랜더링은 끝난다.
자. 이제 추가 , 삭제를 구현해보자.
const dispatch = useDispatch();
useDispatch를 통해서 dispatch에 선언해 준다.
이 useDispatch도 Hooks인데 디스패치를 사용할 수 있게 해준다.
즉 아까 만들어놨던 액션 함수들을
import { insert, remove, toggle } from '../modules/todos';
이렇게 불러와서,
const onInsert = (text) => dispatch(insert(text));
const onRemove = (id) => dispatch(remove(id));
const onToggle = (id) => dispatch(toggle(id));
이런 식으로 사용이 가능하다는 것이다.
그러면 저 변수에 담은 것들을 아까 map 할 때에 넣어주면 된다.
const todosMap = todos.map((todo) => (
<li key={todo.id} onClick={() => onToggle(todo.id)}>
{todo.done ? <s>{todo.text}</s> : <>{todo.text}</>}
<button onClick={() => onRemove(todo.id)}>삭제</button>
</li>
));
이런 식으로 하면 기본적으로 todoList기능을 다 수행한다.
끝~
(중간에 빼먹은 내용이나 부족한 부분이 있으면 댓글 남겨주세요~)
'Redux' 카테고리의 다른 글
Redux toolkit으로 Redux프로처럼 사용해보기 (1) | 2021.04.03 |
---|---|
React_Redux_Typescript_Redux-saga를 개발하고... (0) | 2021.03.27 |
Redux - 몇몇 중요한 규칙 (0) | 2021.01.15 |
Redux의 개념잡기 (0) | 2021.01.15 |
Redux - todolist간단 예제 (1) | 2020.11.30 |