React Hooks学習シリーズ第2弾。
Udemy講座「最短・最速で学ぶ React Hooks 完全ガイド!基礎〜応用編 最新のReact開発+ステート管理をマスターしよう!」のReact Hooksハンズオンの続きです。
useEffectとは?
関数コンポーネントで副作用(Side Effect)を扱う。
副作用とは、DOMの変更・API通信・変数への代入など。
useEffect内に、副作用的処理を書く、という認識でOK
クラスコンポーネントでいう以下に相当する
- componentDidMount
- componentDidUpdate
- componentDidUnmount
Vueで考えたら頻繁に使いそうなメソッド郡ですね。
useEffectの使い方
- コンポーネントにimport
import React, { useState, useEffect } from 'react'
- 関数内でuseEffectを宣言
useEffect(() => {
document.title = `クリック回数: ${count} 回`
})
useEffectには関数を渡す。
また、useEffectは初回render時と更新時に呼び出されるため、componentDidMountとcomponentUpdateの両方の役割を兼ねている。
useEffectの条件設定
useEffectには第2引数に条件を渡すことで発火条件を指定できる。
以下の例では、第2引数にcountを渡しているため、countが変更された時のみuseEffectが発火する。
useEffect(() => {
document.title = `クリック回数: ${count} 回`
console.log('render')
}, [count])
useEffectでイベントリスナーを扱う
useEffectの関数内にdocument.addEventListenerを登録。
useEffect(() => {
console.log('effected')
document.addEventListener('mousemove', getMousePosition)
}, [])
初回レンダリング時のみ実行したい場合、上記のように第2引数には空配列emptyArray[]を入力する。
useEffectでunmount時の処理を書く
第1引数の関数のreturnにremoveEventListenerを含んだ関数を設定することで、componentDidUnmountと同じことができる。
useEffect(() => {
console.log('effected')
document.addEventListener('mousemove', getMousePosition)
return () => { document.removeEventListener('mousemove', getMousePosition) }
}, [])
useEffectでのデータ取得
Mount時にAPIを叩いてデータ取得ができる。update時には発火させたくないので第2引数には[]emptyArrayを入れる。
const fetchData = async () => {
const response = await fetch('https://api.randomuser.me/')
const data = await response.json()
const [item] = data.results
setUser(item)
setLoading(false)
}
useEffect(() => {
fetchData()
}, [])
const [item] = data.results
のようにitemに[]がついているのはdata.resultsが配列を返してきているから。
Contextとは
Contextは「状態」と「状態を管理するメソッド」を、propsを用いず、アプリケーション全体で取り回せるようする
propsはコンポーネント間でバケツリレーすることができるが、コードの記述量が増え、可読性が低くなる。
ContextがDataStoreの役割を果たし、propsを使わずに下層階層のコンポーネントでデータを使うことができる。
useContextはよりシンプルに上記の機能を実現するもの。
useContextの使い方(通常のContextの使い方も)
-
App.jsにCreateContext, useStateをインポート
-
App.jsでcreateContext()
export const userContext = createContext()
- App.jsでstateの準備
const [user, setUser] = useState({ name: 'yamada', age: 32 })
- App.jsでuserContext.Providerを設定
return (
<div className="App">
<userContext.Provider value={user}>
<ComponentC />
</userContext.Provider>
</div>
);
- Contextで囲まれたコンポーネントおよびその下層コンポーネントで、userのstateが使えるようになる! 下位コンポーネントでAppで定義したContextをインポート
import { userContext } from '../App'
- userContext.Consumerの中でstateを参照できる。関数の引数にstateを入れること。
return (
<div>
<userContext.Consumer>
{
user => {
return <div>{user.name}</div>
}
}
</userContext.Consumer>
</div>
)
- ネストすることで複数のContextを扱える
App.js
return (
<div className="App">
<userContext.Provider value={user}>
<languageContext.Provider value={language}>
<ComponentC />
</languageContext.Provider>
</userContext.Provider>
</div>
);
component.js
<userContext.Consumer>
{
user => {
return (
<languageContext.Consumer>
{
language => {
return <div>{user.name}: {language}</div>
}
}
</languageContext.Consumer>
)
}
}
</userContext.Consumer>
外側のConsumerのreturnの中にさらにConsumerを書くので冗長。。。
そこでuseContextの出番!
- useContextをReactからインポート
component.js
import React, { useContext } from 'react'
- useContextの引数にApp.jsでProvideされているContextを渡す
const user = useContext(userContext)
const language = useContext(languageContext)
- あとはjsxに書くだけ。functionのように書く必要なし!ネスト地獄が解消されている
<div>
<div>{user.name}: {language}</div>
</div>