LoginSignup
17
20

More than 3 years have passed since last update.

react hooks+redux toolkitを使ってtodoアプリを作ってみた

Last updated at Posted at 2019-12-08

この記事はTOWN株式会社アドベントカレンダー6日目の記事です(大遅刻して申し訳ないです。。。)
https://adventar.org/calendars/4335

React HooksとはReact16.8から追加された機能で、関数コンポーネントにstateなどの機能を使えるようになった記法です。
https://ja.reactjs.org/docs/hooks-intro.html

Redux toolkitとはどうしても複雑な記述を書かなくてはいけないイメージが(個人的に)あるreduxを簡潔に書くことができるライブラリです。reduxの公式チームがリリースしているそうです。
https://github.com/reduxjs/redux-toolkit

今回はreact hooksとredux toolkitを使ってtodoアプリを作成してみました。

こちらが完成形です。
reduxsample.gif

アプリの作成

まずcreate-react-appを使ってアプリのテンプレートを作成します。

npx create-react-app hooks-toolkit-sample

パッケージをインストールします。

yarn add react-redux @reduxjs/toolkit

or

npm i react-redux @reduxjs/toolkit

yarn startもしくはnpm startでアプリを起動します。reactのロゴsvgなどのいらないファイルやいらない記述等は削除しておきます。

actionとreducerの作成

redux toolkitのcreateSliceを使用し、actionとreducerを同時に作成しています。このおかげでactionとreducerを別々のディレクトリに分ける必要がなくなりました。

modules/listModule.js
import { createSlice } from "@reduxjs/toolkit";

const listModule = createSlice({
    name: "list",
    initialState: [],
    reducers: {
      addList: (state, action) => [...state, action.payload],
      deleteList: (state, action) => state.filter(el => el.id !== action.payload),
    }
});

export default listModule;

storeの作成

reducerとmiddlewareを登録します。先ほどのmoduleのreducerをredux toolkitのcombineReducersを使って登録しています。

src/store.js
import { combineReducers, configureStore } from "@reduxjs/toolkit";
import listModule from "./modules/listModule";

const rootReducer = combineReducers({
    list: listModule.reducer,
});

export const setupStore = () => {
    const store = configureStore({
        reducer: rootReducer,
    });
    return store
}

コンポーネントの作成

まずuseDispatch()を使ってactionが使えるようにします。

todoを追加するためのテキストのinputの操作ですが、inputのonChangehandleChangeList関数を設定して文字を入力するたびに関数が実行されるようにします。
そしてreact hooksのuseStateを用い、入力したテキストを一時的にnewListNameのstateに入れておきます。
addListボタンを押した瞬間にnewListNameを引数にしてactionのaddListを実行し、storeのstateにtodoのテキストが入ることで画面が更新されます。

components/App.js
import React from 'react';
import { useState } from 'react';
import { useDispatch, useSelector } from "react-redux";
import listModule from "../modules/listModule";
import List from "./List.js";

const App = () => {
  const lists = useSelector(state => state.list);

  const [newListName, setListName] = useState("");
  const dispatch = useDispatch();

  const addList = () => {
    if (newListName !== "") {
      dispatch(listModule.actions.addList({id: lists.length > 0 ? lists.reduce((a,b) => a.id > b.id ? a : b).id + 1 : 1, title: newListName}));
    }
    setListName("");
  };

  const handleChangeList = (e) => {
    setListName(e.target.value);
  };

  return (
    <div className="App">
      <p>Redux TODO sample</p>
      {lists.map((list) =>
        <List key={list.id} item={list} />
      )}
      <input type="text" onChange={handleChangeList} value={newListName}/>
      <button onClick={addList}>addList</button>
    </div>
  );
};

export default App;

components/List.js
import React from 'react';
import { useState } from 'react';
import { useDispatch, useSelector } from "react-redux";
import listModule from "../modules/listModule";

const List = (props) => {
  const { item } = props;
  const dispatch = useDispatch();

  const deleteList = () => dispatch(listModule.actions.deleteList(item.id));

  return (
    <div>
      {item.title}
      <button onClick={deleteList}>deleteList</button>
    </div>
  )
}

export default List;

ここまでクラスコンポーネントを使わず、かつとてもコンパクトにreduxのアプリを作成することが出来ました。書いていてかなり楽しかったので今度はもう少し複雑なアプリも作ってみようかと思います。

参考:
TypescriptとReact HooksでReduxはもうしんどくない
https://qiita.com/ky7ieee/items/b3f43ecc497b9115449a
Redux Hooks によるラクラク dispatch & states
https://qiita.com/Ouvill/items/569384e5c8c7ce78f98e
Redux の記述量多すぎなので、 Redux の公式ツールでとことん楽をする。 ( Redux Toolkit)
https://qiita.com/Ouvill/items/a76e9cbce569d01f2931

17
20
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
20