Vue, Nuxtがメインで業務や個人開発をしているはずなのですが、このブログではReactの学習関連が増えてきました笑

React × Reduxのハンズオンが終わったところで、今度はUdemy講座「最短・最速で学ぶ React Hooks 完全ガイド!基礎〜応用編 最新のReact開発+ステート管理をマスターしよう!」でReact Hooksのハンズオンに取り組みます。

React Hooksとは?

React16.8(2019/02リリース)で追加された新機能。

Classを記述せずにローカルステートを作ったりその他のReactで提供されている機能を関数コンポーネントで記述できる。

Hooksはクラスコンポーネントでは使用できないので注意。

100%後方互換性がある = フックには破壊的な変更は一切含まれていない。

完全にオプトイン = 既存のコードを書き換えずに一部のコンポーネントでフックを試すことが可能。

公式
https://ja.reactjs.org/docs/hooks-intro.html

Hooksを使うメリットは?

  • 関数コンポーネントでstate管理ができる
  • ステートを持ったロジックを、コンポーネントの階層構造を変えることなしに再利用できる
  • ラッパー地獄の回避が可能
  • データ取得やEventListenerなどの処理を一つの箇所にまとめることができる
  • DOM変更やデータ取得によるStateの変更などの副作用の処理(関数の外に影響を与えるような処理)を簡単にできる
  • ReduxやMobXを使うことなくstoreの作成が可能

VSCodeスニペット

「ES7 React/Redux/GraphQL/React-Native snippets」を導入。

rceと打つだけで

import React, { Component } from 'react'

export class Counter extends Component {
  render() {
    return (
      <div>
      
      </div>
    )
  }
}

export default Counter

ここまで入力してくれるなど、スニペットがたくさん。

関数ベースならrafcで。

import React from 'react'

export const CountHook = () => {
  return (
    <div>

    </div>
  )
}

フックのルール

  • フックを呼び出すのはトップレベルのみ
  • フックは必ずReactの関数内で用いる

各フックの使い方

useState

変数

  1. ReactからuseStateをインポート
import React, { useState } from 'react'
  1. 変数宣言する。useStateに渡された引数が初期値になる。
const [count, setCount] = useState(0)
  1. stateを更新する関数を準備。setCountの引数がcountの新しい値になる。
const incrementCount = () => {
  setCount(count + 1)
}
  1. 関数コンポーネントなのでrender()不要。Classコンポーネントと比べたとき、constで宣言しているからthisがいらない。this.state.countではなく直接countを見にいけるし、incrementCountでそのまま関数実行できる。
return (
  <div>
    <h1>{count}</h1>
    <button onClick={incrementCount}>CountUp</button>
  </div>
)

Classと比較してめちゃくちゃわかりやすいし楽ですね!!

ループ内で使う場合の注意点

↓動かない

const incrementCountTen = () => {
  for (let i = 0; i < 10; i++) {
    setCount(count + 1)
  }
}

解消のためにはsetCount内には関数を渡す

const incrementCountTen = () => {
  for (let i = 0; i < 10; i++) {
    setCount(prevCount => prevCount + 1)
  }
}

オブジェクト

useStateではオブジェクトも使える。

Vueでいうdata()みたいなものか。

const [name, setName] = useState({ firstName: '', lastName: '' })

オブジェクトを扱う場合、setNameで指定したところでstateの中身を置換してしまう。
NG

<form>
  <input
    type="text"
    value={name.firstName}
    onChange={e => setName({ firstName: e.target.value })}
  />
  <input
    type="text"
    value={name.lastName}
    onChange={e => setName({ lastName: e.target.value })}
  />
</form>

そのため、スプレッド構文を利用して、全てのデータを渡してあげる必要がある。
OK

<form>
  <input
    type="text"
    value={name.firstName}
    onChange={e => setName({ ...name, firstName: e.target.value })}
  />
  <input
    type="text"
    value={name.lastName}
    onChange={e => setName({ ...name, lastName: e.target.value })}
  />
</form>

配列

配列もオブジェクト同様、スプレット構文を忘れずに。

export const ItemHook = () => {
  const [items, setItems] = useState([])
  const addItem = () => {
    setItems([...items, { id: items.length, value: Math.floor(Math.random() * 10)}])
  }
  return (
    <div>
      <button onClick={addItem}>追加</button>
      <ul>
        {
          items.map(item => (
            <li key={item.id}>{item.value}</li>
          ))
        }
      </ul>
    </div>
  )
}

ここまでの所感

  • Hooksわかりやすい!初歩のところだけしかやってないからかもだけど
  • ローカルstateを更新するときにいちいちスプレット構文を添えてあげないといけないのはVue比で少し面倒
  • classコンポーネントより関数コンポーネントにしたい理由がちょっとだけわかった