JS' 공부흔적
[React Redux] React에서 Redux를 사용해보자(1) 본문
이 글은 Redux의 기본 개념에 대해 알고 있다고 가정하고 진행한다. 개념을 잘 모른다면 아래 포스팅을 참고하면 좋을 듯!
[Redux] Vanilla Redux의 기본 개념
Redux는 Javascript의 상태 관리 라이브러리이다. 보통 React와 함께 많이 사용되지만, Augular, jQuery, vanilla JavaScript 등 여러 framework에서 사용이 가능하다. Redux에 기본적인 개념 및 용어를 알아보자..
2junsu.tistory.com
할 일을 추가하고 삭제할 수 있는 간단한 Todo List를 구현하면서 React에서 Redux를 사용하는 법을 알아보자. 이 글에서는 '추가' 기능을 구현한다. 또한 Redux에 익숙해지기 위한 글이므로 Local Storage는 사용하지 않는다. 우선 Redux 사용에 필요한 action, reducer, store는 아래 코드에 바로 작성했다.
import { createStore } from 'redux'
const ADD = 'ADD'
const DELETE = 'DELETE'
//할 일 추가는 text가 필요하다.
const addTodo = (text) => {
return { type: ADD, text }
}
//할 일 삭제는 해당 할 일의 id를 이용하여 찾아낸 후 삭제한다.
const deleteTodo = (id) => {
return { type: DELETE, id }
}
const reducer = (state = [], action) => {
switch (action.type) {
//각 할 일 별로 id를 부여함
case ADD: //state를 mutate 불가
return [...state, { text: action.text, id: Date.now() }]
//filter함수를 사용하여 받은 id의 할 일을 제외하고 나머지를 리턴 -> 받은 id의 할 일만 빠진다.
case DELETE:
return state.filter((e) => e.id !== action.id)
default:
return state
}
}
const store = createStore(reducer)
export const ActionCreators = { addTodo, deleteTodo } //Action Creator
export default store
위의 코드에서 잘 봐야할 것은 reducer의 ADD 부분이다. Todo List에 할 일을 추가하는 부분인데, 이를 배열에 저장한다. 일반적으로는 배열의 push() 함수를 사용하여 값을 추가하지만, reducer는 다르다. Redux의 state는 불변성을 유지해야 한다. 즉, state를 mutate할 수 없다는 말인데 이는 state의 값을 직접 다이렉트로 변경할 수 없다는 말이다. 따라서 배열의 push() 함수를 사용하여 배열의 값을 직접적으로 변경할 수 없고, 간접적으로 새로운 배열을 생성하여 이 배열을 반환해야 한다. 이 부분은 중요하니까 꼭 알아뒀으면 한다!
Vanilla Redux에서 다룬 개념 중 dispatch, getState, subscribe는 쓰이지 않았는데 React Redux에서는 사용하는 법이 약간 다르다. mapDispatchToProps, mapStateToProps, connect가 그 방법인데 이는 주로 예전에 쓰이던 방법이고, 요즘에는 Hook을 사용하여 더 편리하게 Redux에 접근할 수 있는 방법이 등장했기 때문에 이 방법으로 설명하겠다. 그러나 클래스형 컴포넌트를 사용한다면 Hook을 사용하지 못 하므로 아래의 Docs를 참고하길 바란다.
React Redux | React Redux
Official React bindings for Redux
react-redux.js.org
npm install react-redux
yarn add react-redux
useDispatch
dispatch를 React Redux에서는 useDispatch로 사용한다. 사용법은 거의 비슷하다. 우리가 Todo List에서 dispatch가 필요한 곳은 할 일을 추가하거나 삭제할 때이다. 할 일을 추가할 때부터 보면 입력했을 때 dispatch가 발생해야 한다. 따라서 form 태그를 사용하여 간단한 입력 폼을 만들고 onSubmit을 사용하여 dispatch를 구현할 수 있다.
import React, { useState } from 'react'
import Todo from './Todo'
import { useDispatch } from 'react-redux'
import { ActionCreators } from './redux/store'
const App = () => {
const dispatch = useDispatch() //useDispatch Hook을 사용하는 방법
const [text, setText] = useState('')
const onChange = (e) => {
setText(e.target.value)
}
const onSubmit = (e) => {
e.preventDefault() //제출을 해도 페이지가 넘어가지 않도록 유지
console.log(text)
dispatch(ActionCreators.addTodo(text)) //addTodo함수로 action 생성 후 dispatch
setText('')
}
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
}}
>
<h1>react redux 연습</h1>
<form onSubmit={onSubmit}>
<input type="text" value={text} onChange={onChange} />
<button>ADD</button>
</form>
...
</div>
)
}
export default App
useSelector
getState()는 useSelector라는 Hook을 사용하여 구현한다. store에서 원하는 값을 골라온다는 뜻이다. 이것의 사용 방법도 복잡하지 않다. 단지 아래의 코드만 추가해주면 된다.
import { useSelector } from 'react-redux'
const todoList = useSelector((state) => state)
console.log(todoList) //값을 확인하기 위함
input 창에 '잠자기'를 입력한 후 로그를 찍어보면 아래와 같이 뜬다.
따라서 이 데이터를 화면에 뿌려주기만 하면 '추가' 기능은 완성이다!
//App.js
import React, { useState } from 'react'
import Todo from './Todo'
import { useDispatch, useSelector } from 'react-redux'
import { ActionCreators } from './redux/store'
const App = () => {
const dispatch = useDispatch()
const todoList = useSelector((state) => state)
console.log(todoList)
const [text, setText] = useState('')
const onChange = (e) => {
setText(e.target.value)
}
const onSubmit = (e) => {
e.preventDefault()
console.log(text)
dispatch(ActionCreators.addTodo(text))
setText('')
}
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
}}
>
<h1>react redux 연습</h1>
<form onSubmit={onSubmit}>
<input type="text" value={text} onChange={onChange} />
<button>ADD</button>
</form>
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
width: 300,
}}
>
<h3>할 일</h3>
<ul>
{todoList.map((e) => (
<Todo key={e.id} {...e} />
))}
</ul>
</div>
</div>
)
}
export default App
//Todo.js
import React from 'react'
const Todo = (text) => {
return (
<li>
{text} <button>DEL</button>
</li>
)
}
export Todo