Wiz テックブログ

Wizは、最新のIoTやICTサービスをお客様に届ける「ITの総合商社」です。

Reactコードレビュー会を行いました。

こんにちは、フロントエンドエンジニアの仲本です。

Wizの新プロジェクトにてフロントエンドをReactを使用して実装しました。

新プロジェクトのフェーズ1が終了とフェーズ2の間で一度リファクタリングを行おうと思い今回コードレビュー会を開きました。

コードレビュー以外にもNext.jsについての話も盛り上がったのですが、今回はコードレビューの内容のみお届けします。

コードレビューでご指摘していただいた中から2つほど紹介いたします。

使用技術

  • React
  • Redux-toolkit
  • Emotion

fetchの共通化

ある程度fetchをする回数が増えてくると、bodyを書いたりheadersでcontent-typeを毎回書くのはつらなくなってきます。

なので、fetchを共通化させます。

修正前

こちらがログイン処理などをまとめているsliceになります。

現在例で出している処理は、違うタイプの処理ではありますが認証タイプの処理は他のAPIで使用することもあるので共通化させておくと実装する際に楽になります。

import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
import { apiURL } from '../../utils/constants'

export interface loginFormInput {
  mailAddress: string;
  passWord: string;
}

export const fetchAsyncLogin = createAsyncThunk('login', async (data: loginFormInput) => {
  //  ログインAPI
  const loginParams = {
    login_id: data.mailAddress,
    password: data.passWord
  }
  const res = await fetch(`${apiURL}/login`, {
    method: 'POST',
    body: JSON.stringify(loginParams),
    headers: {
      'Content-Type': 'application/json'
    },
  })
  return res.json()
})

export const fetchAsyncAuth = createAsyncThunk('auth', async (data: {token: string}) => {
  //  認証API
  const res = await fetch(`${apiURL}/auth`, {
    method: 'POST',
    mode: 'cors',
    headers: {
      Authorization: `Bearer ${data.token}`
    },
  })
  return res.json()
})
~~省略~~

修正後

通化用ファイルを作成します。

// post用 認証なし
export const fetchPostNoAuth = async (url: string, params) => {
  const res = await fetch(url, {
    method: 'POST',
    body: JSON.stringify(params),
    headers: {
      'Content-Type': 'application/json'
    },
  })
  return res.json()
}

// 認証付きAPI bodyなし
export const noBodyFetch = async (url: string, token: string, method: 'GET'|'PATCH'|'POST') => {
  const res = await fetch(url, {
    method: method,
    mode: 'cors',
    headers: {
      Authorization: `Bearer ${token}`
    }
  })
  return res.json()
}

// 認証付きAPI bodyあり
export const bodyFetch = async (url: string, token: string, method: 'POST' | 'PATCH', body: string) => {
  const res = await fetch(url, {
    method: method,
    mode: 'cors',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${token}`
    },
    body: body
  })
  return res.json()
} 

通化を行ったら、先程のsliceも変更します。

import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
import Cookies from 'js-cookie'
import { apiURL } from '../../utils/constants'
import { fetchPostNoAuth, noBodyFetch } from '../../../ts/fetch'

// 非同期はSliceの外に出してcreateAsyncThunkを使用する
export interface loginFormInput {
  mailAddress: string;
  passWord: string;
};


export const fetchAsyncLogin = createAsyncThunk('login', async (data: loginFormInput) => {
  //  ログインAPI
  const loginParams = {
    login_id: data.mailAddress,
    password: data.passWord
  }
  const url = `${apiURL}/login`
  const fetchLogin = fetchPostNoAuth(url, loginParams)
  return fetchLogin
})

export const fetchAsyncAuth = createAsyncThunk('auth', async (data: {token: string}) => {
  //  認証API
  const url = `${apiURL}/auth`
  return noBodyFetch(url, data.token, 'POST')
})

結構スッキリしました。

Error Boundaryの追加

最後にErrorBoudaryの追加です。

ErrorBoudaryとは

自身の子コンポーネントツリーで発生した JavaScript エラーをキャッチし、エラーを記録し、クラッシュしたコンポーネントツリーの代わりにフォールバック用の UI を表示する React コンポーネントです。 (引用: React公式|Error Boudanry

React16からコンポーネント内でエラーが発生した場合、React コンポーネントツリー全体がアンマウントされてしまうので追加する必要があります。

実装

import React from 'react'
import { ErrorBlock } from './views/components/block/Error';


type Props = {
  children: JSX.Element
}

class ErrorBoundary extends React.Component<Props, { hasError: boolean }> {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  render() {
    if (this.state!.hasError) {
      return <ErrorBlock />;
    }

    return this.props.children;
  }
}

export default ErrorBoundary

上記がErrorBoudary検知用のコンポーネントになります。 コードの説明します。

あとはこちらをエラー時にマウントさせたい場所でimportします。

import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import store from './stores'
import { jsx } from '@emotion/react'
import GlobalStyle from './style/GlobalStyle'
import 'react-hot-loader'


const app = document.getElementById('app')
//component
import Routing from './Routing'
import ErrorBoundary from './ErrorBoundary'


ReactDOM.render(
  <ErrorBoundary>
    <Provider store={store}>
      <GlobalStyle />
      <Routing />
    </Provider>
  </ErrorBoundary>
  ,
  app
)

if (module.hot) {
  module.hot.accept()
}

おわりに

以上がコードレビュー会での指摘された内容でした。

今後はredux周りのパフォーマンスチューニングを行っていきたいと思っています。 またその際は記事にしてアップしたいと思います。

ここまで読んで頂き、ありがとうございます。


Wizではエンジニアを募集しております。

興味のある方、ぜひご覧下さい。

careers.012grp.co.jp