どうもこんにちは、たくびー(@takubii)です。
最近、Reduxのチュートリアルをハンズオンで実践しました。
今回はそこで得たReduxの基本的な使い方について書いていきたいと思います。
※なお、今記事ではチュートリアルのPart4くらいまでの情報を取り上げます。Part7,8のRTK Queryについては触れません。
最終的には以下のようなアプリを作成できます。
公式チュートリアルに記載されていたSandboxを添付します。
チュートリアルの所感
Reduxのチュートリアルの通してやってみた感想としては、自分が今Reduxを使うのに必要としている部分まで進めれば十分だなと感じました。
私が個人的に感じたReduxのチュートリアルの大まかなまとまりを以下にまとめます。
Part1、Part2
上記の2つのセクションはcreate react appのReduxテンプレートで作成できるカウンターアプリを見ながらReduxの説明をしています。
この2つのセクションでは手を動かさなさいので人によっては退屈に感じるかもしれません。
Part3、Part4、Part5
上記の3つのセクションは実際に手を動かしながらRedux上でデータの保存や取得を行っています。
正直ここまでやればReduxについては十分な知識が得られると思います。
アプリもほぼ完成系になるので、実際のアプリに使用できると思います。
Part6
このセクションではSliceを作成するのをさらに便利にするcreateEntityAdapter
についての解説が主です。
セクションの最後で「チュートリアルはこれで全てです」とWebサイト上に記載されているため、Reduxの想定ではここまで使用するのがベターなのではないでしょうか。
正直、ツールにかなり依存してしまっているので、このセクションで使用する技術を使うとRedux Tool Kitにかなり合わせる必要があると思います。
Part7,Part8
RTK Queryという通信部分に関するライブラリの説明です。
正直かなり難しいです。理解するにはRTK Query自体の知識も必要になると思います。
チュートリアル内でもおまけのような扱いとなっているので、この2つのセクションをやるかどうかは好みになってきます。
各セクションごとに私の所感を述べました。
もし、Reduxのチュートリアルに手をつけてみたいという方はこちらの所感を参考にしていただけると幸いです。
※チュートリアルを進める際の注意点として、Node.jsのバージョンが16以前でないとエラーが発生するのでそこだけ注意してください。
Sliceの作成
現在のReduxではRedux Tool Kitの利用が主流となっています。
その中のAPIであるcreateSlice
について解説します。
まずは以下のコードをご覧ください。
import { createSlice } from '@reduxjs/toolkit'
const initialState = [
{ id: '1', title: 'First Post!', content: 'Hello!' },
{ id: '2', title: 'Second Post', content: 'More text' },
]
const postsSlice = createSlice({
name: 'posts'
initialState,
reducers: {
postAdded(state, action) {
state.push(action.payload)
},
},
});
export const { postAdded } = postsSlice.actions
export const selectAllPosts = (state) => state.posts
export const selectPostById = (state, userId) => state.posts.find((post) => post.id === userId)
export default postsSlice.reducer
上記のコードはSNSの投稿に関するSlice
と考えてください。
createSlice
はReduxで使用するために使われるAction creatorやReducerなどを作成してくれる便利な関数です。
ここでは以下の項目が必須になります。
- name
- initialState
- reducers
これらを定義したpostsSlice
を通してpostsSlice.actions
でアクションクリエーターを、postsSlice.reducer
でリデューサーを取得できます。
作成したSliceの登録
Sliceを作成したらStoreに登録しStateを取り出せるように設定する必要があります。
以下のコードのようになります。
import { configureStore } from '@reduxjs/toolkit'
import postsReducer from '../features/posts/postsSlice'
export default configureStore({
reducer: {
posts: postsReducer,
},
})
configureStore
関数のreducer
オブジェクトにKey,Value形式で登録します。
こちらで登録したKeyの値を使うことで、後々に出てくるuseSelector
などでStoreから特定のStateを取得できます。
コンポーネントでの使用
Storeからデータを取得する場合、useSelector
関数を使用してデータを取得します。
Sliceで定義したselectAllPosts
を引数として与えると、それに応じたStateの結果が返ってきます。
import React from 'react'
import { useSelector } from 'react-redux'
import { selectAllPosts } from './features/posts/postsSlice'
export const PostsList = () => {
const posts = useSelector(selectAllPosts)
const renderedPosts = posts.map((post) => (
<article className="post-excerpt" key={post.id}>
<h3>{post.title}</h3>
<p className="post-content">{post.content.substring(0, 100)}</p>
</article>
))
return (
<section className="posts-list">
<h2>Posts</h2>
{renderedPosts}
</section>
)
}
また、createSlice
で定義したアクションを実行する場合は、useDispatch
関数を使用します。
const dispatch = useDispatch()
のようにディスパッチ関数を取得し、ディスパッチ関数にcreateSlice
で定義したアクションクリエータと引数を渡すことで実行することができます。
今回の場合はStore
に新しい項目の追加を行っています。
import React, { useState } from 'react'
import { useDispatch } from 'react-redux'
import { nanoid } from '@reduxjs/toolkit'
import { postAdded } from './postsSlice'
export const AddPostForm = () => {
const [title, setTitle] = useState('')
const [content, setContent] = useState('')
const dispatch = useDispatch()
const onTitleChanged = (e) => setTitle(e.target.value)
const onContentChanged = (e) => setContent(e.target.value)
const onSavePostClicked = () => {
if (title && content) {
dispatch(
postAdded({
id: nanoid(),
title,
content,
})
)
setTitle('')
setContent('')
}
}
return (
<section>
<h2>Add a New Post</h2>
<form>
<label htmlFor="postTitle">Post Title:</label>
<input
type="text"
id="postTitle"
name="postTitle"
value={title}
onChange={onTitleChanged}
/>
<label htmlFor="postContent">Content:</label>
<textarea
id="postContent"
name="postContent"
value={content}
onChange={onContentChanged}
/>
<button type="button" onClick={onSavePostClicked}>
Save Post
</button>
</form>
</section>
)
}
まとめ
基本的な使い方はここまで見てきた方法の通りになります。
Reduxを使用する上で、その背後の概念を理解することがとても重要だと感じました。
一見、使用する変数などが散見していたり、様々な関数を使用したりと複雑に思えますが、内部でどのような動きを行なっているのかを理解すると挙動の理解も早まると思います。
この部分に関してはチュートリアルの1〜3章をじっくり読みながら、実際に手を動かして学ぶことをおすすめします。
Reduxの公式チュートリアルにはまだまだ便利な機能や非同期でのStateの更新など見どころがあるのでぜひ目を通してみてください。
また、今回私が実践したチュートリアルについては以下のリポジトリを参照してください。
終わりに
今回は最近学んだReduxの簡単な使い方について紹介しました。
Stateの管理には様々なライブラリがありますのでアプリによって適したものを選ぶのが一番だと思いますが、候補として最初に上がりそうなのがReduxだと思います。
この記事が少しでもReduxの理解の助けになれば嬉しいです。
今回はこの辺りで締めたいと思います。
また機会があればお会いしましょう。