概要
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
の説明としては本当にざっくりでしたので、詳細は公式ドキュメントで確認ください。