리덕스 기본 모듈 만들기에서 만든 모듈들을 이용해 여러가지 기능들을 구현해본다.
카운터 구현하기
프리젠테이셔널 컴포넌트
프리젠테이셔널 컴포넌트를 만들건데 프리젠테이셔널 컴포넌트란, 리덕스 스토어에 직접 접근하지 않고 필요한 값 또는 함수를 props 로 받아와서 사용하는 컴포넌트이다.
프리젠테이셔널 컴포넌트는 주로 UI 를 선언하는 것에 집중하고, 필요한 값, 함수를 props로 받아와 사용한다.
먼저 components 폴더를 만들고 새로운 파일을 작성한다.
//components/Counter.js
import React from "react";
function Counter({ number, diff, onIncrease, onDecrease, onSetDiff }) {
const onChange = (e) => {
onSetDiff(parseInt(e.target.value, 10));
};
return (
<div>
<h1>{number}</h1>
<div>
<input type="number" value={diff} onChange={onChange} />
<button onClick={onIncrease}>+</button>
<button onClick={onDecrease}>-</button>
</div>
</div>
);
}
export default Counter;
컨데이너 컴포넌트
컨테이너 컴포넌트란 리덕스 스토어의 상태 조회, 액션 디스패치를 할 수 있는 컴포넌트를 의미하는데 HTML 태그들을 사용하지 않고 프리젠테이셔널 컴포넌트들을 불러와서 사용한다.
리덕스 스토어를 조회하기 위해서는 useSelector
를 사용하는데 이때 파라미터로 받는 state
는 store.getState()
함수에서 반환하는 객체와 동일하다.
dispatch 를 사용하기 위해서는 useDispatch
를 사용한다.
//containers/CounterContainers.js
import React from "react";
import { useSelector, useDispatch } from "react-redux";
import Counter from "../components/Counter";
import { decrease, increase, setDiff } from "../modules/counter";
function CounterContainers() {
//상태조회를 위한 함수
//state = store.getState() 와 결과물 동일, 즉 현재의 상태
const { number, diff } = useSelector((state) => ({
number: state.counter.number,
diff: state.counter.diff,
}));
const dispatch = useDispatch();
//counter.js 에서 작성한 액션생성함수로 dispatch
//함수를 만들어 호출하면 액션을 만들고 이를 디스패치 한다.
const onIncrease = () => dispatch(increase());
const onDecrease = () => dispatch(decrease());
const onSetDiff = (diff) => dispatch(setDiff(diff));
//만든것들을 전부 Counter 에 전달해주면 된다.
return (
<Counter
number={number}
diff={diff}
onIncrease={onIncrease}
onDecrease={onDecrease}
onSetDiff={onSetDiff}
></Counter>
);
}
export default CounterContainers;
할일목록(todos) 구현하기
프리젠테이셔널 컴포넌트
세가지의 프리젠테이셔널 컴포넌트를 만들건데
- TodoItem(하나의 할일 목록)
- TodoList(TodoItem 을 보여주는 리스트)
- Todos(TodoList 와 새로운 목록 추가하는 폼)
세가지다.
//components/Todos.js
import React, { useState } from "react";
const TodoItem = React.memo(function TodoItem({ todo, onToggle }) {
//todo = todos 모듈안의 state 객체
return (
<li
style=
onClick={() => onToggle(todo.id)}
>
{todo.text}
{todo.done}
</li>
);
});
const TodoList = React.memo(function TodoList({ todos, onToggle }) {
return (
<ul>
{todos.map((todo) => (
//키값 잊지 말것
<TodoItem key={todo.id} todo={todo} onToggle={onToggle}></TodoItem>
))}
</ul>
);
});
function Todos({ todos, onCreate, onToggle }) {
//리덕스를 사용한다고 모든 상태관리를 리덕스에서 할 필요는 없다.
const [text, setText] = useState("");
const onChange = (e) => setText(e.target.value);
const onSubmit = (e) => {
e.preventDefault();
onCreate(text);
setText("");
};
//목록을 추가하기 위한 폼과 TodoList
return (
<div>
<form onSubmit={onSubmit}>
<input
type="text"
value={text}
onChange={onChange}
placeholder="할 일을 입력하세요"
/>
<button type="submit">등록</button>
</form>
<TodoList todos={todos} onToggle={onToggle}></TodoList>
</div>
);
}
export default React.memo(Todos);
React.memo 를 사용해 최적화 작업을 해줬다.
컨데이너 컴포넌트
//containers/TodosContainer.js
import React, { useCallback } from "react";
import { useSelector, useDispatch } from "react-redux";
import Todos from "../components/Todos";
import { addTodo, toggleTodo } from "../modules/todos";
function TodosContainers() {
const todos = useSelector((state) => state.todos);
const dispatch = useDispatch();
//useCallback 으로 최적화
const onCreate = useCallback((text) => dispatch(addTodo(text)), [dispatch]);
const onToggle = useCallback((id) => dispatch(toggleTodo(id)), [dispatch]);
return <Todos todos={todos} onCreate={onCreate} onToggle={onToggle}></Todos>;
}
export default TodosContainers;
0
- ㅇㄴㅁㄴㅇㅁ
- ㅇㄴㅁㅇㄴㅁ
- ㅈㅂㄷㅈㅂ
- ㅀㄷㅈㅎㄱ
잘 작동된다.