saitoxu.io

AboutTwitterGitHub

React+ReduxでAJAXを使ったアプリを作ってみる

April 16, 2017

Redux 公式のページで紹介されている AJAX を使ったアプリをベースに、 GitHub の公開リポジトリを取得するアプリを作ってみました。

React Redux Async Sample

動作イメージ ↓

Anime

環境

  • react 15.5.4
  • redux 3.6.0
  • react-redux 5.0.4
  • redux-thunk 2.2.0

手順

大まかなステップだけ説明します。

1. State を決める

最初にアプリケーション全体の State を決めます。 今回は以下のように単純な形でいきます。

{
  username: "saitoxu",
  isFetching: false,
  repos: [
    { name: "repo1" },
    { name: "repo2" },
    { name: "repo3" }
  ]
}

2. Action の定義

Action はリクエストを送るときのREQUEST_REPOSと、 レスポンスを受け取ったときのRECEIVE_REPOSの 2 種類定義します。

GitHub の公開リポジトリを取得するのは Fetch API を使いました。

export const REQUEST_REPOS = 'REQUEST_REPOS'
export const RECEIVE_REPOS = 'RECEIVE_REPOS'
export function fetchReposIfNeeded(username) {
return (dispatch, getState) => {
if (shouldFetchRepos(getState(), username)) {
return dispatch(fetchRepos(username))
}
}
}
function fetchRepos(username) {
return (dispatch) => {
dispatch(requestRepos(username))
return fetch(`https://api.github.com/users/${username}/repos`)
.then((response) => {
return response.json()
})
.then((json) => {
if (json.message) {
throw Error(json.message)
}
return dispatch(receiveRepos(username, json))
})
.catch((err) => {
return dispatch(receiveRepos(username, []))
})
}
}
function requestRepos(username) {
return {
type: REQUEST_REPOS,
username
}
}
function receiveRepos(username, json) {
return {
type: RECEIVE_REPOS,
username,
repos: json.map(child => {
return { name: child.name }
})
}
}
function shouldFetchRepos(state, username = '') {
const currentUsername = state.username
const isFetching = state.isFetching
if (username.length === 0 || currentUsername === username || isFetching) {
return false
}
return true
}
view raw actions.js hosted with ❤ by GitHub

3. Reducer を作る

次に、Reducer を作ります。 今回は State が単純なので、Reducer は 1 つだけで OK です。

import { combineReducers } from 'redux'
import {
REQUEST_REPOS,
RECEIVE_REPOS
} from './actions'
function reposByUser(state = { username: '', isFetching: false, repos: [] }, action) {
switch (action.type) {
case REQUEST_REPOS:
return Object.assign({}, state, {
username: action.username,
isFetching: true
})
case RECEIVE_REPOS:
return Object.assign({}, state, {
isFetching: false,
repos: action.repos
})
default:
return state
}
}
const rootReducer = combineReducers({
reposByUser
})
export default rootReducer
view raw reducers.js hosted with ❤ by GitHub

4. Store を作る

Reducer から Store を作るのは簡単です。 非同期リクエストを扱うので、redux-thunk で提供されているthunkMiddlewareをかませます。

import { createStore, applyMiddleware } from 'redux'
import thunkMiddleware from 'redux-thunk'
import rootReducer from './reducers'
export default function configureStore(preloadedState) {
return createStore(
rootReducer,
preloadedState,
applyMiddleware(
thunkMiddleware
)
)
}
view raw configureStore.js hosted with ❤ by GitHub

残りはGistにあげているので確認してみてください。