【必読】React開発で役に立つTips 8選

以下は、[jsmanifest](https://twitter.com/jsmanifest)さんの記事、[8 Useful Practices for React Apps You Should Know](https://dev.to/jsmanifest/8-useful-practices-for-react-apps-you-should-know-5k9)の日本語訳です。

# 【必読】Reactアプリで役に立つプラクティス8選（8 Useful Practices for React Apps You Should Know）

[medium](https://medium.com/@jsmanifest)で私を見つけてくださいね。

Reactはとても多くのステージへの変化を行ってきました。そしてそれらは、必ず私達を驚かせます。

最初、私達は[mixins](https://www.reddit.com/r/reactjs/comments/alc005/what_exactly_is_a_mixin/)を使って、インターフェースを作ったり管理したりしていました。そして次に[クラスコンポーネント](https://reactjs.org/docs/react-component.html)というコンセプトが到来し、現在は、Reactでの私達の開発方法を変える[react hooks](https://reactjs.org/docs/hooks-intro.html)です。

他になにか素晴らしいことを知っていますか？ 例えば、Reactで使える、アプリをより良くするのに役立つ巧みなトリックです。

この記事では、全てのReactデベロッパーが知っておくべき8つの高度なトリックを紹介します。このリストの全てがあなたにとって目新しいものではないと思いまが、最低でも1つ、便利なトリックを見つけることを願っています。

これが、あなたが知っておくべきreactで使える8つのトリックです。

## 1. 文字列でReact要素を生成する（Create react elements with strings）

まず1つ目は、HTML DOMタグを表すシンプルな文字列でReact DOM要素を作る方法です。

例えば、変数に`div`という文字列を代入することで、Reactコンポーネントを作ることができます。

```jsx

import React from 'react'

const MyComponent = 'div'

function App() {
  return (
    <div>
      <h1>Hello</h1>
      <hr />
      <MyComponent>
        <h3>I am inside a {'<div />'} element</h3>
      </MyComponent>
    </div>
  )
}
```

Reactは、`React.createElement`を呼び、与えられた文字列を使って、内部で要素を生成します。これってクールでしょ？

[Material-UI](https://material-ui.com/)のようなコンポーネントライブラリでよく使われます。コンポーネントのルートnodeを決める`component`propsを宣言できます。

```jsx

function MyComponent({ component: Component = 'div', name, age, email }) {
  return (
    <Component>
      <h1>Hi {name}</h1>
      <div>
        <h6>You are {age} years old</h6>
        <small>Your email is {email}</small>
      </div>
    </Component>
  )
}
```

このように使用することができます。

```jsx
function App() {
  return (
    <div>
      <MyComponent component="div" name="George" age={16} email="george@gmail.com">
    </div>
  )
}
```

カスタムコンポーネントを渡すこともできます。

```jsx

function Dashboard({ children }) {
  return (
    <div style={{ padding: '25px 12px' }}>
      {children}
    </div>
  )
}

function App() {
  return (
    <div>
      <MyComponent component={Dashboard} name="George" age={16} email="george@gmail.com">
    </div>
  )
}
```

## 2. Error Boundariesを使う（Use Error Boundaries）

JavaScriptでは、私達はほとんどのエラーを`try/catch` ー発生したエラーを"catch"できるコードのブロックー で対応しています。エラーがcatchブロックに補足された時、私達はアプリがクラッシュするのを避けることができます。

例はこのようなものです。

```jsx
function getFromLocalStorage(key, value) {
  try {
    const data = window.localStorage.get(key)
    return JSON.parse(data)
  } catch (error) {
    console.error
  }
}
```

Reactは結局ただのJavaScriptなので、エラーをキャッチしてハンドルできると考えるでしょう。しかし、Reactの性質上、コンポーネント内でのJavScriptエラーは内部のstateを破壊し、将来のレンダーにおいて[cryptic errors](https://github.com/facebook/react/issues/4026)（不可解なエラー）を引き起こします。

このような理由で、Reactチームは[Error Boundaries](https://reactjs.org/docs/error-boundaries.html)を紹介しています。そして全てのReactデベロッパーがそれらを知っておくべきです。そうすれば自らのReactアプリで使用することができます。

Error Boundaries登場以前のエラー発生の問題点は、これらの不可解なエラーが発生した時、Reactはそれらに対処したり、リカバリーする方法を私達に与えていなかったことです。ですので、私達は皆Error Boundariesが必要なのです。

Error Boundariesは、Reactコンポーネントです。コンポーネントツリーのどこででもエラーをキャッチすることができ、ログ出力し、クラッシュしたコンポーネントツリーの代わりにフォールバック用UIを表示させることができます。Error Boundariesは、レンダー中、ライフサイクルメソッド内、そしてError Boundaries以下に存在する全体のツリーのコンストラクタ内でエラーをキャッチします（そしてこれが、私達のアプリのトップのどこかでError Boundariesを宣言しレンダーする理由です）。

```jsx
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props)
    this.state = { hasError: false }
  }

  static getDerivedStateFromError(error) {
    // Update state so the next render will show the fallback UI.
    return { hasError: true }
  }

  componentDidCatch(error, errorInfo) {
    // You can also log the error to an error reporting service
    logErrorToMyService(error, errorInfo)
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>
    }

    return this.props.children
  }
}
```

そして、普通のコンポーネントと同じように使用できます。

```jsx
<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>
```

## 3. 前回の値を保持する（Retain Previous Values）

propsやstateを更新している時、あなたは`React.useRef`を使ってそれらの前回の値を保持することができます。

例えば、1つの配列のアイテムの、現在と前回の変更を追跡するために、前回の値が割り当てられる`React.useRef`と、現在の値が割り振られる`React.useState`を使用することができます。

```jsx
function MyComponent() {
  const [names, setNames] = React.useState(['bob'])
  const prevNamesRef = React.useRef([])

  React.useEffect(() => {
    prevNamesRef.current = names
  })

  const prevNames = prevNamesRef.current

  return (
    <div>
      <h4>Current names:</h4>
      <ul>
        {names.map((name) => (
          <li key={name}>{name}</li>
        ))}
      </ul>
      <h4>Previous names:</h4>
      <ul>
        {prevNames.map((prevName) => (
          <li key={prevName}>{prevName}</li>
        ))}
      </ul>
    </div>
  )
}
```

これは正しく動作します。なぜなら`React.useEffect`はレンダーが完了した後に実行されるからです。

`setNames`が実行される時、コンポーネントは再度レンダーを行い、`prefNamesRef`は前回の値を保持します。なぜなら、前回のレンダーから見て`React.useEffect`が最後に実行されるコードだからです。
そして`useEffect`内で`prevNamesRef.current`に値が再び代入されるので、次回のレンダー時には前回のnamesの値を保持します。

## 4. 値チェックにReact.useRefを使う（Use React.useRef for flexible non-stale value checks）

React Hooksが登場する以前、ComponentがDOMにマウントされた**後**に、dataのフェッチなどの処理を行いたい場合、私達は`componentDidMount`というクラスコンポーネントのStaticメソッドを使用していました。

React Hooksが発表された時、それはすぐにコンポーネントを書く最も人気の手段となりました。コンポーネントがアンマウントされた後にstateがセットされるのを防ぐために、コンポーネントがマウントされたかを監視したい時、私達はこのようにするでしょう。

```jsx
import React from 'react'
import axios from 'axios'

class MyComponent extends React.Component {
  mounted = false

  state = {
    frogs: [],
    error: null,
  }

  componentDidMount() {
    this.mounted = true
  }

  componentWillUnmount() {
    this.mounted = false
  }

  async fetchFrogs = (params) => {
    try {
      const response = await axios.get('https://some-frogs-api.com/v1/', { params })
      if (this.mounted) {
        this.setState({ frogs: response.data.items })
      }
    } catch (error) {
      if (this.mounted) {
        this.setState({ error })
      }
    }
  }

  render() {
    return (
      <div>
        <h4>Frogs:</h4>
        <ul>
        {this.state.frogs.map((frog) => <li key={frog.name}>{frog.name}</li>
        )}
        </ul>
    </div>
    )
  }
}
```

React Hooksに統合後、Hooksは`componentDidMount`を持っていません。そして、アンマウント後に起こったstateアップデートによるメモリリークのコンセプトは未だにhooksに当てはまります。しかし、React Hooksを使った`componentDidMount`に似た方法は`React.useEffect`を使用することです。なぜなら、それはコンポーネントがレンダリングされた後に実行されるからです。もしあなたが`React.useRef`を使って、マウントされた値を割り当てるなら、以下のクラスコンポーネントの例で同じことができます。

```jsx
import React from 'react'
import axios from 'axios'

function MyComponent() {
  const [frogs, setFrogs] = React.useState([])
  const [error, setError] = React.useState(null)
  const mounted = React.useRef(false)

  async function fetchFrogs(params) {
    try {
      const response = await axios.get('https://some-frogs-api.com/v1/', {
        params,
      })
      if (mounted.current) {
        setFrogs(response.data.items)
      }
    } catch (error) {
      if (mounted.current) {
        setError(error)
      }
    }
  }

  React.useEffect(() => {
    mounted.current = true

    return function cleanup() {
      mounted.current = false
    }
  }, [])

  return (
    <div>
      <h4>Frogs:</h4>
      <ul>
        {this.state.frogs.map((frog) => (
          <li key={frog.name}>{frog.name}</li>
        ))}
      </ul>
    </div>
  )
}
```

リレンダーをせず最新の変更をトラッキングするもう一つ別の例は、以下のように、`React.useMemo`と併せて使用することです。([source](https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/utils/useForkRef.js))

```jsx
function setRef(ref, value) {
  // Using function callback version
  if (typeof ref === 'function') {
    ref(value)
    // Using the React.useRef() version
  } else if (ref) {
    ref.current = value
  }
}

function useForkRef(refA, refB) {
  return React.useMemo(() => {
    if (refA == null && refB == null) {
      return null
    }
    return (refValue) => {
      setRef(refA, refValue)
      setRef(refB, refValue)
    }
  }, [refA, refB])
}
```
もしref propsが変更され、定義されたら、新たな関数を作ります。
つまり、Reactは古いフォークされたrefをnull、新しいフォークされたrefを現在のrefで呼ぶことを意味します。そして`React.useMemo`が使われているので、refの変数たちは`refA`または`refB`のref propsが変更されるまで記憶されます。ナチュラルなクリーンアップが起こるのです。

## 5. 他の要素に依存したカスタム要素にReact.useRefを使う（Use React.useRef for customizing elements that depend on other elements）

`React.useRef`にはいくつか役に立つユースケースがあります。例えば、`React.useRef`自体をref propsに割り当てるなどです。

```jsx
function MyComponent() {
  const [position, setPosition] = React.useState({ x: 0, y: 0 })
  const nodeRef = React.useRef()

  React.useEffect(() => {
    const pos = nodeRef.current.getBoundingClientRect()
    setPosition({
      x: pos.x,
      y: pos.y,
    })
  }, [])

  return (
    <div ref={nodeRef}>
      <h2>Hello</h2>
    </div>
  )
}
```
もし`div`要素の座標位置を取得したいなら、この例が役に立ちます。しかし、アプリケーションのどこかに存在する別の要素の位置をアップデートしたかったり、それに応じて条件ロジックを変更したり適応する場合、ベストな方法は`ref callback function pattern`を使うことです。callback function patternを使用すると、ReactコンポーネントまたはHTML DOM要素を第一引数として受け取ります。

下の例は、コールバック関数である`setRef`がどこで`ref` propsに適応されるかを示すシンプルなものです。直接`React.useRef`をDOM要素に割り当てるのとは対象的に、`setRef`の内側では必要なことは何でもできるということがわかります:

```jsx
const SomeComponent = function({ nodeRef }) {
  const ownRef = React.useRef()

  function setRef(e) {
    if (e && nodeRef.current) {
      const codeElementBounds = nodeRef.current.getBoundingClientRect()
      // Log the <pre> element's position + size
      console.log(`Code element's bounds: ${JSON.stringify(codeElementBounds)}`)
      ownRef.current = e
    }
  }

  return (
    <div
      ref={setRef}
      style={{ width: '100%', height: 100, background: 'green' }}
    />
  )
}

function App() {
  const [items, setItems] = React.useState([])
  const nodeRef = React.useRef()

  const addItems = React.useCallback(() => {
    const itemNum = items.length
    setItems((prevItems) => [
      ...prevItems,
      {
        [`item${itemNum}`]: `I am item # ${itemNum}'`,
      },
    ])
  }, [items, setItems])

  return (
    <div style={{ border: '1px solid teal', width: 500, margin: 'auto' }}>
      <button type="button" onClick={addItems}>
        Add Item
      </button>
      <SomeComponent nodeRef={nodeRef} />
      <div ref={nodeRef}>
        <pre>
          <code>{JSON.stringify(items, null, 2)}</code>
        </pre>
      </div>
    </div>
  )
}
```

## 6. 高階コンポーネント（Higher Order Components）
プレインなJavaScriptで強力な再利用性を持つ関数を作るよくあるパターンは高階関数です。Reactも結局はJavaScriptなので、内部で高階関数を使用することができます。

再利用性のあるコンポーネントには、高階コンポーネントとというトリックが使えます。

高階コンポーネントとは、あなたがコンポーネントを引数にして、返り値としてコンポーネントを返す関数を持っているときのことです。高階関数がロジックを抽象化し、他の関数間で共有されるように、高階コンポーネントもコンポーネントをロジックから切り離し、他のコンポーネント間で共有することができます。つまり、たくさんの再利用可能なコンポーネントを採用し、アプリケーション内で実際に繰り返し使うことが可能だということなのです。

これは高階コンポーネントの例です。このスニペットでは、高階コンポーネントであるwithBorderはカスタムコンポーネントを引数として取り込み、隠された**ミドルレイヤー**コンポーネントを返します。そして、親がこの高階コンポーネントをレンダーするとき、これはコンポーネントとして呼ばれ、**ミドルレイヤー**コンポーネントからから渡されたpropsを受け取ります。

```jsx
import React from 'react'

// Higher order component
const withBorder = (Component, customStyle) => {
  class WithBorder extends React.Component {
    render() {
      const style = {
        border: this.props.customStyle
          ? this.props.customStyle.border
          : '3px solid teal',
      }
      return <Component style={style} {...this.props} />
    }
  }

  return WithBorder
}

function MyComponent({ style, ...rest }) {
  return (
    <div style={style} {...rest}>
      <h2>This is my component and I am expecting some styles.</h2>
    </div>
  )
}

export default withBorder(MyComponent, {
  border: '4px solid teal',
})
```

## 7. Render Props
React内で使う私のお気に入りのトリックの一つは、render prop patternです。複数のコンポーネントでコードを共有するという問題を解決する点において、これは高階コンポーネントに似ています。Render propsは、レンダーに必要なものを全て差し戻すことが目的の関数をはっきりとさせます。

Reactでコンポーネントをレンダーする最もベーシックな方法は、このようなものでしょう。

```jsx
function MyComponent() {
  return <p>My component</p>
}

function App() {
  const [fetching, setFetching] = React.useState(false)
  const [fetched, setFetched] = React.useState(false)
  const [fetchError, setFetchError] = React.useState(null)
  const [frogs, setFrogs] = React.useState([])

  React.useEffect(() => {
    setFetching(true)
    api
      .fetchFrogs({ limit: 1000 })
      .then((result) => {
        setFrogs(result.data.items)
        setFetched(true)
        setFetching(false)
      })
      .catch((error) => {
        setError(error)
        setFetching(false)
      })
  }, [])

  return (
    <MyComponent
      fetching={fetching}
      fetched={fetched}
      fetchError={fetchError}
      frogs={frogs}
    />
  )
}
```

Render Propsを使う場合は、その子をレンダーするpropは慣例的にrenderと呼ばれます。

```jsx
function MyComponent({ render }) {
  const [fetching, setFetching] = React.useState(false)
  const [fetched, setFetched] = React.useState(false)
  const [fetchError, setFetchError] = React.useState(null)
  const [frogs, setFrogs] = React.useState([])

  React.useEffect(() => {
    setFetching(true)
    api
      .fetchFrogs({ limit: 1000 })
      .then((result) => {
        setFrogs(result.data.items)
        setFetched(true)
        setFetching(false)
      })
      .catch((error) => {
        setError(error)
        setFetching(false)
      })
  }, [])

  return render({
    fetching,
    fetched,
    fetchError,
    frogs,
  })
}
```

この例では、`MyComponent`は***render prop component***として参照するコンポーネントの例です。なぜなら、`MyComponent`はpropとしての`render`を期待していますし、子をレンダーするためのそれを実行するからです。
これはReactにおいて、とてもパワフルなパターンです。renderのコールバックを通して引数として、共有されたstateとdataを渡すことができるのです。複数のコンポーネントにおいて、そのコンポーネントはリレンダーされ、再利用されることが可能になります。

```jsx
function App() {
  return (
    <MyComponent
      render={({ fetching, fetched, fetchError, frogs }) => (
        <div>
          {fetching
            ? 'Fetching frogs...'
            : fetched
            ? 'The frogs have been fetched!'
            : fetchError
            ? `An error occurred while fetching the list of frogs: ${fetchError.message}`
            : null}
          <hr />
          <ul
            style={{
              padding: 12,
            }}
          >
            {frogs.map((frog) => (
              <li key={frog.name}>
                <div>Frog's name: {frog.name}</div>
                <div>Frog's age: {frog.age}</div>
                <div>Frog's gender: {frog.gender}</div>
              </li>
            ))}
          </ul>
        </div>
      )}
    />
  )
}
```

## 8. Memoize

Reactデベロッパーとして知っておくべき最も大事なことの一つは、`React.memo`のようなコンポーネントのパフォーマンス最適化です。それを知っておくと、無限ループのようなとてもひどいエラーを防ぐことができます。

Reactアプリにおいて、Memoization（メモ化）を行う、いくつかの方法があるので是非読んでみてください。

* [React.memo](https://reactjs.org/docs/react-api.html#reactmemo)
* [React.useMemo](https://flaviocopes.com/react-hook-usememo/)
* [React.useCallback](https://reactjs.org/docs/hooks-reference.html#usecallback)
* [React.PureComponent](https://reactjs.org/docs/react-api.html#reactpurecomponent)
* [Optimizing performance](https://reactjs.org/docs/optimizing-performance.html)

## 締め

ここでこの投稿は終わりです！この記事があなたにとって価値があることを願います。

[Medium](https://medium.com/@jsmanifest)も見てくださいね。

## 感想

まず、今回の記事は翻訳が難しかったです。英語もさることながら、自分のReact Hooksの理解が浅いなと実感しました。
逆にReact HooksやよりReactの理解が進めば、これらのトリックはとても役に立ちそうだと思いました。

間違い等見つけましたら教えていただけるとありがたいです。