概要
React16.8から新しい機能としてHooksが導入されました。
以下の順序でHooksとは何かざっくり入門していきましょう。
Hooksとは?
Hooksとは従来__classコンポーネント__でしか使用できなかったstate等の機能を__functionalコンポーネント(関数コンポーネント)__でも使用可能にする機能です。
この記事では以下の3種類のhookを紹介します。
- (1)State Hook:
stateやsetStateを関数コンポーネント内で使用可能にする。 - (2)Effect Hook:データ取得やDOM変更といった
side effectsを関数コンポーネント内で使用可能にする。 - (3)Custom Hooks:共通のロジックをコンポーネント間での再利用を可能にする。
Hooksの規則
Hooksを使用する際には以下の規則を守りましょう。
- (1) Hooksは必ずコンポーネント中の一番上(
トップレベル)に定義する。 - ループ、条件分岐、ネストされた関数の中で定義してはいけません。)
- (2) HooksはReactの関数コンポーネントの中だけで呼ぶ。(通常のJavascriptの関数から使用してはいけません。)
State Hook
useStateと呼ばれるhookを使用する事でstateやsetStateを関数コンポーネント内で行える様にします。
classコンポーネントとuseStateを使用した関数コンポーネントを比較して使用方法を確認して見ましょう。
従来のclassコンポーネント
以下の例では主に2つの事を行なっています。
- (1)
stateで初期値に0を持つcountを定義する。 - (2)
setStateでボタンを押すたびにcountに1を足している。
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>{this.state.count} 回クリックしました。</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
クリックしてください。
</button>
</div>
);
}
}
StateHook
上記と全く同じ事をuseStateを使用して行います。
基本的な使用方法(定義方法)は以下の通りです。
const [state, setState] = useState(initialState);
useStateでは従来のstateとsetStateを同時に設定しする様なイメージです。
上記のcountやそのsetStateをuseStateを使用して定義すると以下の様になります。
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0)
}
以下の3点に注目して上のコードを見てみましょう。
- (1)
countがclassコンポーネントでいうthis.state={count:0}の部分。 - (2)
setCountがclassコンポーネントでいうsetStateの部分。 - (3)
useState()に渡されている0がcountの初期値。
また以下の2点を踏まえて残りのコードを完成させます。
- (1)
stateを直接参照できる。 - (2)
setCountを使用してstateを更新できる。
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0)
return(
<div>
// (1) stateを直接参照できる。
<p>{count} 回クリックしました</p>
// (2) setCountを使用してstateを更新できる。
<button onClick={() => setCount(count + 1)}> クリックしてください。</button>
</div>
)
}
export default Counter;
ちなみに以下の様にして複数のstateを定義していきます。
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0)
const [name, setName] = useState('')
return(
<div>
<p>{count} 回クリックしました</p>
<button onClick={() => setCount(count + 1)}> クリックしてください。</button>
<p>私の名前は{name}</p>
<button onClick={() => setName('テスト太郎')}>名前表示</button>
</div>
)
}
export default Counter;
Effect Hook
従来のclassコンポーネントではcomponentDidMountやcomponentDidUpdate、componentWillUnmount等の中でデータ取得やDOM変更を行なっていましたが、これをuseEffectと呼ばれるhookを使用し、関数コンポーネントでも使用可能にします。
こちらもuseEffectの使用方法を従来のclassコンポーネントと比較して確認していきます。
従来のclassコンポーネント
従来はcomponentDidMountはマウントされた直後に1回だけ呼ばれ、componentDidUpdateはコンポーネントが更新された後に呼ばれ、ここでデータの取得等を行いました。
import React from 'react';
class Effect extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
componentDidMount() {
console.log('マウントされました。')
}
componentDidUpdate() {
console.log('アップデートされました。')
}
render() {
return (
<div>
<h1>{this.state.count} 回クリックしました。</h1>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
クリックしてください。
</button>
</div>
);
}
}
EffectHook
useEffectは従来のcomponentDidMount、componentDidUpdate、componentWillUnmountの3つを組み合わせた様なもので、基本的にrenderされる毎に呼ばれます。(first renderを含む。)
hooksを使用した開発ではここでside effectsを実行します。
import React, { useState, useEffect } from 'react'
function Effect() {
const [count, setCount] = useState(0)
useEffect(() => {
console.log('レンダーされました。')
})
return(
<div>
<h1>{count} 回クリックしました</h1>
<button onClick={() => setCount(count + 1)}> クリックしてください。</button>
</div>
);
}
Custom Hooks
上記で記載した通り、共通のロジックをコンポーネント間での再利用を可能にします。
以下の2つのコンポーネントがあるとします。
- (1) 受け取った
idが1だったらログイン中ですを返す、status.js、 - (2) 受け取った
idが1だったらおかえりなさいを返すmessage.js。
export default function Status(props){
const [isLoggedIn, setIsLoggedIn] = useState(false);
const handleStateChange = (id) => {
if(id === 1){
setIsLoggedIn(true)
}
else{
setIsLoggedIn(false)
}
}
useEffect(() => {
handleStateChange(props.user.id)
})
const status = isLoggedIn ? 'ログイン中' : 'サインアップ'
return (
<>
<h1>Status: {status}</h1>
</>
)
}
export default function Message(props){
const [isLoggedIn, setIsLoggedIn] = useState(false);
const handleStateChange = (id) => {
if(id === 1){
setIsLoggedIn(true)
}
else{
setIsLoggedIn(false)
}
}
useEffect(() => {
handleStateChange(props.user.id)
})
const message = isLoggedIn ? 'おかえりなさい' : 'あなたは誰ですか?'
return (
<>
<h1>Message: {message}</h1>
</>
)
}
ここの共通したロジック部分をcustom Hookを使用する事で、以下の様に抜き出す事ができます。
※抜き出したロジックのコンポーネントはuseから始まる慣習があります。今回はuseLoginと名付けました。
import { useState, useEffect } from 'react';
export default function useLogin(userId){
const [isLoggedIn, setIsLoggedIn] = useState(false);
// コンポーネント間で再利用したいロジック
const handleStateChange = (id) => {
if(id === 1){
setIsLoggedIn(true)
}
else{
setIsLoggedIn(false)
}
}
// side effectsを実行する。
useEffect(() => {
handleStateChange(userId)
})
return isLoggedIn;
}
useLoginを使用する事でstatus.jsとmessage.jsをよりスッキリ書くことができます。
import React from 'react';
import useLogin from './useLogin';
export default function Status(props){
const status = useLogin(props.user.id) ? 'ログイン中' : 'サインアップ'
return (
<>
<h1>Status: {status}</h1>
</>
)
}
import React from 'react';
import useLogin from './useLogin';
export default function Message(props){
const message = useLogin(props.user.id) ? 'おかえりなさい' : 'サインアップしてください'
return (
<>
<h1>Message: {message}</h1>
</>
)
}
custom hooksでは他にも色々な事ができるので、詳細は公式ドキュメントで確認ください。
参照
hooksの説明としては本当にざっくりでしたので、詳細は公式ドキュメントで確認ください。


