0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Reduxを学んだ(2) ~Middleware編(e.g. ReduxThunk)~

Last updated at Posted at 2021-01-04

Reduxミドルウェアとは?

  • store.dispatchが呼び出れてから実際にstateを更新されるまでの間に、処理を挟み込むためのもの

Reduxミドルウェアの例

Loggerミドルウェア

  • 以下みたいな感じで実装できるだろう。
    const logger = (state) => (next) => (action) => {
      console.group(action.type)
        console.log('The action: ', action)
        const result = next(action)         // 次の処理
        console.log('The new state :', store.getState())
      console.groupEnd()
      return result
    }

ReduxThunkミドルウェア

ライブラリとして提供される。中身の骨格は以下のような感じである。


    const thunk = (store) => (next) => (action) => {
      if (typeof action === 'function') {
        // これを満たすactionは"handleDeleteTodo(todo)の返り値のcallback関数"とか
        return action(store.dispatch)
      }
      return next(action)
    }

要は、dispatchに渡されるactionが、(オブジェクトではなく)callback関数の時に発動される。このcallback関数は、dispatchを引数に取り、行いたい処理を行うcallback関数であることを前提としている。


    // Action Creator
    function handleInitialData() {
      return (dispatch) => {          // callback関数を返している
        return Promise.all([
          API.fetchTodos(),
          API.fetchGoals()
        ]).then(([todos,  goals]) => {
          dispatch(receiveDataAction(todos, goals))     // 新たにactionを初期化してdispatchしている
        })
      }
    }


    class App extends React.Component {
      componentDidMount () {
        const { dispatch } = this.props
        dispatch(handleInitialData())        // callback関数が渡されている -> Redux Thunksミドルウェアで処理される
      }

     render(){...}
    }

Redux Thunkミドルウェアは主に非同期処理を行いたい時に使用できる。これを使用することで、APIリクエストを行うdata fetchingのコードをComponentの中ではなく、ActionCreatorの中に含めることができる。

ミドルウェアの中で新たにactionがdispatchされるというところが面白い。

ミドルウェアの使用方法

    const store = Redux.createStore(
      Redux.combineReducers({todos, goals}),
      Redux.applyMiddleware(ReduxThunk.default, checker, logger)
    )

おまけ1(Optismistic UI)

itemの削除時はUIで一旦消してしまう。API通信でDBの更新に失敗した場合は、そのitemを復活させる。

    class Todos extends React.Component {
      addItem = (e) => {
        e.preventDefault()
        const name = this.input.value

        // 新しくTodoが作られる時、そのidはサーバーサイドで作られるので、
        // UIをoptimistic updateすることはしない
        return API.saveTodo(this.input.value)
          .then((todo) => {
            this.props.store.dispatch(addTodoAction(todo))
            this.input.value = ''
          })
          .catch(() => {
            alert('An error occurred when adding Todo. Try again!')
          })
      }

      removeItem = (todo) => {
        this.props.store.dispatch(removeTodoAction(todo.id))
        return API.deleteTodo(todo.id)
          .catch(() => {
            // Optimistic UI
            // これだとstore.todosの末尾に追加されるのでtodosの並びが変わるが、、、
            this.props.store.dispatch(addTodoAction(todo))
            alert('An error occurred when removing Todo. Try again!')
          })
      }

      render() {...}
    }

おまけ2(inputタグのSingle Source of Truth)

inputタグについて、「ユーザの入力内容をstateに保持し、随時更新すべきである」「inputの中のvalueは随時このstateを反映すべきである」(single source of truthを実現するため)というのが面白かったのでメモっておく。

    class Todos extends React.Component {
      addItem = (e) => {
        e.preventDefault()
        this.props.dispatch(handleAddTodo(
          this.input.value,
          () => this.input.value = ''
        ))
      }

      render() {
        return (
          <div>
            <h1>Todos</h1>
            <input
              type='text'
              placeholder='Add Todo'
              // inputのvalueが更新されるたびに、input DOM(要はrefを含んでいるDOM)を引数にこのcallback関数が実行される
              // つまり、ユーザが入力した内容は随時state(input)に保持される!
              ref={(input) => this.input = input}
            />
            <button onClick={this.addItem}>Add Todo</button>
          </div>
        )
      }
    }
0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?