LoginSignup
11
6

More than 3 years have passed since last update.

Redux ToolkitでLoadingの状態を管理する

Last updated at Posted at 2020-12-15

何をやるか

SPAを扱う上で、どのタイミングでローディングの表示をするのか、どのように管理するのか。
結構考えるのめんどくさいと思います。
↓こんなやつ
b39f6ff59f51a613294a5f21ef9382de.gif

Redux Toolkitを使えばシンプルにかけたので備忘録として残しておきます:writing_hand:
どのようにローディング状態管理しよう…とお考えの方がいれば、その解決の一つになればと思います:eyes:

使用している技術

  • React (reactHooks)
  • Redux (Redux-toolkit)
  • TypeScript

機能

今回はAPIを叩いてpending中にloadingを表示、
処理が終了したらloadingを非表示という機能を想定して書いていきます。

redux toolkitが用意してくれているextraReducersという機能を使って実装します!

pending → 実行開始〜結果が帰ってくるまでの間
fulfilled → 正常終了
rejected → エラー

となっているので、以下のように、
pendingの時のみ、isLoadingという項目をtrueにすることで、
APIが実行開始〜結果が帰ってくるまでの間の状態を管理します。

sampleSlice.tsx

import { createSlice, createAsyncThunk } from "@reduxjs/toolkit"
import { fetchGet } from "./common/fetch"

interface selectUserProps {
  isLogin: boolean
}

// ↓このAPIを叩く想定で進める
export const getInfo = createAsyncThunk("admin/post",async () => {
  const url = "叩くAPIのURL"
  const result = await fetchGet(url)
  return result
  }
)

const sampleSlice = createSlice({
  name: "sample",
  // ↓初期値
  initialState: {
    isLoading:false
  },

  // extraReducersで状態をLoading管理する
  extraReducers: (builder) => {
    builder.addCase(getInfo.pending, (state, action) => {
      // APIの処理が始まったら isLoadingをtrueに
      state.isLoading = true
    })
    builder.addCase(getInfo.rejected, (state, action) => {
      // 失敗したら isLoadingをfalseに 
      state.isLoading = false
    })
    builder.addCase(getInfo.fulfilled, (state, action) => {
      // 成功しても isLoadingをfalseに 
      state.isLoading = false
    })
  },
})


// ローディング状態をexport
export const selectLoading = (state: any): selectUserProps => state.sample.isLoading
export default sampleSlice.reducer

fetch.ts

// 別に切り分けた関数
import axios from "axios"
axios.defaults.withCredentials = true

export const getInfo = async(url:string) =>{
  const result = await axios(url, {
    method: 'GET',
    )
  return result.data
}

UI

UI上では、スピナーを作成して、
先程のloading状態をインポートし、trueの場合だけ作成したスピナーを表示させます。

スピナー

画面全体にLoadingを表示させるコンポーネントです。
(待っている間はユーザー側の入力ができないので、ユーザー操作できるようにするには調整必要です)

fixedSpinner.tsx
import React, { useEffect, useState } from 'react'
import { css } from '@emotion/core'
import { Spinner } from '../../components/atoms/Spinner'

export const FixedSpinner = () => {
  return (
    <div css={spinnerOverRay}>
      <div css={spinnerWrap}>
        <Spinner />
      </div>
    </div>
  )
}

const spinnerOverRay = css`
  position: fixed;
  -ms-transform: translate(-50%, -50%);
  height: 100vh;
  width: 100vw;
  z-index: 999;
  background-color: rgba(245, 245, 245, 0.5);
`
const spinnerWrap = css`
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
`
Spinner.tsx
import React from 'react'
import { css } from '@emotion/core'

export const Spinner = () => {
  return <div css={spinner} />
}


export const spinner = css`
  width: 50px;
  height: 50px;
  border: 10px solid #dddddd;
  border-top-color: #aaaaaa;
  border-radius: 50%;
  animation: 1s spin infinite linear;
  @keyframes spin {
    from {
      transform: rotateZ(0deg);
    }
    to {
      transform: rotateZ(360deg);
    }
  }
`

Loading表示

useSelectorを使って、loading状態を取得し、
trueの場合のみ、先程作成したスピナーを表示します。

sample.tsx

import React from 'react'

// components
import { FixedSpinner } from '../../components/block/FixedSpinner'

// store
import { getInfo, selectLoading } from '../../../stores/slices/sampleSlice'

export const Sample = ({ setPath }: any) => {
  const dispatch = useDispatch()
  const loading = useSelector(selectLoading)

  const handleSubmit = () => {
    dispatch(getInfo())
  }

  return (
    <div>
      // loading が true の時、FixedSpinnerを表示
      {loading && <FixedSpinner />}
       <button css={SubmitBtn} onClick={handleSubmit}>
         API叩く
       </button>
    </div>
  )
}

感想

Redux Toolkitを使えば簡単にloadingの管理ができてハッピーでした:clap:
コンポーネントも使いまわせるので、使える部分はこれ使っていこうかな〜と考えております。

もっといい方法あればご教示ください:pray:

11
6
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
11
6