LoginSignup
14
4

More than 5 years have passed since last update.

ReduxでAPIから取得したデータを保持するのが嫌になったのでaxiosで保持してみた

Last updated at Posted at 2017-08-17

ReduxのGlobalStateでAPIのデータを保持するか否か

Reduxではredux-thunkやredux-sagaを用いてaction内でAPIリクエストした結果をGlobalStateに保持するのがお約束になっていますが、そもそも

action作成

reducerにcase追加

containerのmapStateToPropsで受け取る

というプロセスが非常にめんどくさい。
しかもGlobalStateにAPIデータが保持されているかどうかで分岐もさせないといけない。

それならaxiosのPromiseをキャッシュしておいて、2度目以降同じaxios.getリクエストをした場合にそのキャッシュを返せばいんじゃね?
ということでaxios.getをキャッシュする仕組みを作ってみました。

注意点として、この中でキャッシュと呼んでいるものは永続的なものでなくリロードすると消えるものです。

使用するモジュール

・Webpack (3.0.0)
・axios (0.16.2)

コード

URLとクエリパラメータが完全に一致するキャッシュが存在する場合にのみキャッシュを返します。
また allowedCaches.js に指定したパターンに一致するリクエストのみキャッシュします。

./src/axios-cache/index.js
import 'babel-polyfill';
import allowedCaches from './allowedCaches';

/**
 * keyをソートして返却
 * @param {object} object
 * @return {object}
 */
function objectSort(object) {
  let array = [];
  for (let key in object) {
    if (object.hasOwnProperty(key)) {
      array.push(key);
    }
  }

  array.sort();

  let sorted = {};
  for (let i = 0; i < array.length; i++) {
    sorted[array[i]] = object[array[i]];
  }

  return sorted;
}

/**
 * @param {object} params
 * @return {string}
 */
function createQuery(params) {
  params = objectSort(params);

  let ary = [];
  Object.keys(params).forEach(function(key) {
    ary.push(`${key}=${encodeURIComponent(params[key])}`);
  });
  return ary.join('&');
}

function match(url) {
  for (let i=0; i < allowedCaches.length; i++) {
    const allowedUrl = allowedCaches[i];
    if (url.match(new RegExp(allowedUrl))) {
      return true;
    }
  }
  return false;
}

/**
 * @param {Axios} axios - axios instance
 */
export function cachingGet(axios) {
  const get = axios.get;
  const cache = new Map();

  axios.get = function cachedGet(url, config) {
    const key = (config && config.params) ? `${url}?${createQuery(config.params)}` : url;
    if (cache.has(key)) {
      return cache.get(key);
    } else {
      const request = get.apply(axios, arguments);
      if (match(url)) {
        cache.set(key, request);
      }
      return request;
    }
  };
}

./src/axios-cache/allowedCaches.js
export default [
  '/api/users.*' // 正規表現
];

使い方

./src/main.js
import axios from 'axios'
import { cachingGet } from './axios-cache'

const axiosInstance = axios.create();
cachingGet(axiosInstance);

axiosInstance.get('/api/users');
// 2度目以降はキャッシュしたpromiseインスタンスが返却される
axiosInstance.get('/api/users');

// クエリパラメータまで一致しない場合、別のリクエストとみなす
axiosInstance.get('/api/users?a=b');
axiosInstance.get('/api/users?a=c');
14
4
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
14
4