考古学 : react-reduxを学ぶ
2022/06/26
概要
Hooks対応前のReact(v16.6.3)および、react-redux(v5.1.1)、redux(3.6.0)のプロダクションコードを触る機会があり、色々学んだ内容などをメモる。
2017~2018年あたりのReact + Reduxの実装パターンを学ぶことができました。
当時のReact + Redux構成
ディレクトリ構成
src/
├── actions/
│ └── index.js
├── components/
│ ├── App.js
│ └── TodoList.js
├── containers/
│ └── VisibleTodoList.js
├── reducers/
│ └── index.js
└── index.js
Reduxの基本パターン
Actions
// actions/index.js
export const ADD_TODO = 'ADD_TODO'
export const TOGGLE_TODO = 'TOGGLE_TODO'
export function addTodo(text) {
return {
type: ADD_TODO,
text
}
}
export function toggleTodo(id) {
return {
type: TOGGLE_TODO,
id
}
}
Reducers
// reducers/index.js
import { ADD_TODO, TOGGLE_TODO } from '../actions'
const initialState = {
todos: []
}
function todoApp(state = initialState, action) {
switch (action.type) {
case ADD_TODO:
return {
...state,
todos: [
...state.todos,
{
id: Date.now(),
text: action.text,
completed: false
}
]
}
case TOGGLE_TODO:
return {
...state,
todos: state.todos.map(todo =>
todo.id === action.id
? { ...todo, completed: !todo.completed }
: todo
)
}
default:
return state
}
}
export default todoApp
Container Components
// containers/VisibleTodoList.js
import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'
const mapStateToProps = state => ({
todos: state.todos
})
const mapDispatchToProps = dispatch => ({
onTodoClick: id => {
dispatch(toggleTodo(id))
}
})
export default connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
Presentational Components
// components/TodoList.js
import React from 'react'
const TodoList = ({ todos, onTodoClick }) => (
<ul>
{todos.map(todo => (
<li
key={todo.id}
onClick={() => onTodoClick(todo.id)}
style={{
textDecoration: todo.completed ? 'line-through' : 'none'
}}
>
{todo.text}
</li>
))}
</ul>
)
export default TodoList
現代のReact + Reduxとの違い
Hooks以前
connect()HOCを使用mapStateToPropsとmapDispatchToPropsを定義- Container ComponentsとPresentational Componentsの分離
Hooks以降
useSelectorとuseDispatchを使用- Container Componentsが不要に
- よりシンプルな実装
import { useSelector, useDispatch } from 'react-redux'
import { toggleTodo } from '../actions'
const TodoList = () => {
const todos = useSelector(state => state.todos)
const dispatch = useDispatch()
return (
<ul>
{todos.map(todo => (
<li
key={todo.id}
onClick={() => dispatch(toggleTodo(todo.id))}
style={{
textDecoration: todo.completed ? 'line-through' : 'none'
}}
>
{todo.text}
</li>
))}
</ul>
)
}
学んだこと
- Reduxの基本的な設計パターン
- Container/Presentationalパターンの意義
- Hooksによる実装の簡略化の恩恵
- レガシーコードを読むことの重要性
まとめ
レガシーなReact + Reduxのコードを読むことで、現代のReactがいかに進化してきたかを実感できました。
Hooksの登場により、コードがよりシンプルで読みやすくなったことを改めて認識できました。