LoginSignup
17
11

More than 5 years have passed since last update.

Reactでpost後のレスポンスを使ったページ遷移をredux-sagaとreact-routerで行う方法

Last updated at Posted at 2017-11-16

概要

post後のパラメータidを取得して、redux-sagaを呼び出すとき、(id) => {this.props.history.push(/items/${id})としてcallbackをaction.payloadで渡して、実行すればOK

使いどころ

  • 新規アイテム作成ダイアログにおいて、アイテム名入力後に自動的にアイテム表示画面に遷移させる
  • ユーザー登録画面において、ユーザー作成後に自動的にユーザー情報表示画面に遷移させる

実現したいページ遷移イメージ

(今回のコードに色々くっつければ、こんな感じのページ遷移になるよというイメージ)
https://gyazo.com/186ed16e427f297d3a88ba3b5e7f5892

環境

  • react-router: 4.2.0
  • react-router-dom: 4.2.2
  • redux-saga: 0.16.0
  • react-routerでhisotry.pushができるようになっている。参考
  • (サーバー側はrailsのwebpackerつかってます。)

方法

想定する状況は、redux-sagaでpostが既に実装されていて、そこにページ遷移機能を追加するときです。
説明の都合上postの実装も前準備で説明します。

前準備

(本質ではないので読み飛ばしてもOK)

api

postのapiを準備します。サーバー側のコードは省略します。動きだけを説明すると
1. あるitemのnameをpostする
2. postが成功するとサーバー側では新たなidを持つitemが作成される。
3. レスポンスとして、response.data.statusには'ok'、result.idにidがかえってくる

apiのコードは下記の通り。至って普通。

app/javascript/modules/Api.js
import axios from 'axios'

const axiosPost = ({url, data}) => {
  return (
    axios.post(url, data)
      .then(
        response => {
          console.log('success');
          return (response);
        }
      )
  )
};

export const createItem = (data) => axiosPost({url: '/api/v1/items', data: data});

手順

要点は、sagaで実行するためにaction.payloadに関数をわたすこと。このわたす関数をreact-routerの関数にします。そうすれば、sagaのタスク内からreact-routerの関数を実行できます。

action

渡す関数をcallbackとしてactionを下記のように定義します。(nameは、itemを作成するためのパラメータですが、それぞれの実装に合わせて適宜変えてください。)

app/javascript/actions/items.js
export const CREATE_ITEM = 'CREATE_ITEM';

export const createItem = (name, callback) => {
  return {
    type: CREATE_ITEM,
    payload: {name: name, callback: callback}
  }
};

saga

sagaのタスク内でaction.payload.callbackを呼び出します。postのレスポンスにidが乗っているのでそれをcallbackの引数にします(それぞれの状況でことなるとはおもいますが)。
既にpost用のコードが書かれていて、idを引数にしたnavigationであれば、action.payload.callback(id)の箇所を追加するだけだとおもいます。

app/javascript/sagas/mySaga.js
import {call, put, takeLatest} from 'redux-saga/effects'
import {createItem} from '../modules/Api'
import {CREATE_ITEM} from '../actions/items'
import 'babel-polyfill' // ジェネレータ関数を使うために必須

export function* createItemFlow(action) {
  if (params.name) {
    const response = yield call(createItem, {name: action.payload.name})
    if (response.data.status === 'ok') {
      const id = response.data.result.id
      action.payload.callback(id) // action.payload.callbackにreact-routerのhistory.pushするcallbackを載せてここで呼び出す
    }
  }
}

function* mySaga() {
  yield takeLatest(CREATE_ITEM, createItemFlow);
}

export default mySaga;

component

最後にcomponentでcallbackにreact-routerの関数をのせてsagaを呼び出すようにします。

component/ItemCreationDialog.jsx
import React from 'react'
import {connect} from 'react-redux'
import {createItem} from '../actions/items'
import {withRouter} from 'react-router';

class ItemCreationDialog extends React.Component {
// 省略
  handleCreateItem = () => {
      this.props.createItem(
        this.state.name, // action.payload.nameに渡される
        (id) => {this.props.history.push(`/items/${id}`)} // action.payload.callbackに渡される
      )
  };

  render() {
    return (
    <div>
        // this.handleCreateItemを呼び出す処理。//
    </div>
    )
  }
}

export default withRouter(connect(state => {return (state)},{createItem})(ItemCreationDialog))

参考

雑談

  • redux-saga覚えたおかげでreactが楽しくなった。viewからロジックをsagaにうつすとcomponentがすっきりするから、書いていてつらくない。
  • react-routerを使うと、railsのノリでSPAが書けるので設計が楽になった。
17
11
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
17
11