Help us understand the problem. What is going on with this article?

React hooksを基礎から理解する (useEffect編)

React hooksとは

React 16.8 で追加された新機能です。
クラスを書かなくても、stateなどのReactの機能を、関数コンポーネントでシンプルに扱えるようになりました。

useEffectとは

useEffectを使うと、useEffectに渡された関数はレンダーの結果が画面に反映された後に動作します。
つまりuseEffectとは、「関数の実行タイミングをReactのレンダリング後まで遅らせるhook」になります。

副作用の処理(DOMの書き換え、変数代入、API通信など)を関数コンポーネントで扱えます。
クラスコンポーネントでのライフサイクルメソッドに当たります。

  • componentDidMount
  • componentDidUpdate
  • componentWillUnmount

参考:React公式サイト 副作用フックの利用法

create-react-appでReactのコードを書く

create-react-appをひさしぶりに npm installしようとしたらテンプレートが出来ない😦
困っていて見つけた記事。解決出来ました。ありがとうございます。

参考:ひさしぶりにcreate-react-appしたらテンプレートができなかった時の対処法

Material-UIをinstall

Material-UIをinstallしたら、使いたいコンポーネントをすぐ見つけられるし、勝手にスタイリングしてくれるのでテンションあがります😁

$ npm install @material-ui/core

参考:MATERIAL-UI

クリックしたらタイトルも同時に変更されるコンポーネントを作る

クラスコンポーネント

react.js
import React, { Component } from 'react'
import ButtonGroup from '@material-ui/core/ButtonGroup';
import Button from '@material-ui/core/Button';

class EffectClass extends Component {
  constructor(props){
    super(props);
    this.state = {
      count: 0,
    }
  }

  componentDidMount(){
    document.title =`${this.state.count}回クリックされました`
  }

  componentDidUpdate(){
    document.title =`${this.state.count}回クリックされました`
  }

  render() {
    return (
      <>
        <p>{`${this.state.count}回クリックされました`}</p>
        <ButtonGroup color="primary" aria-label="outlined primary button group">
          <Button onClick={()=> this.setState({count: this.state.count + 1})} >
            ボタン
          </Button>
          <Button onClick={()=> this.setState({count: 0})}>
            リセット
          </Button>
        </ButtonGroup>
      </>
    )
  }
}

export default EffectClass

関数コンポーネント

react.js
import React, {useState, useEffect} from 'react'
import ButtonGroup from '@material-ui/core/ButtonGroup'
import Button from '@material-ui/core/Button'

const EffectFunc = () => {
  const [count, setCount] = useState(0)
  useEffect(() => {
    document.title =`${count}回クリックされました`
  })

  return (
    <>
      <p>{`${count}回クリックされました`}</p>
      <ButtonGroup color="primary" aria-label="outlined primary button group">
        <Button onClick={()=>setCount((prev) => prev + 1)}>
          ボタン
        </Button>
        <Button onClick={()=>setCount(0)}>
          リセット
        </Button>
      </ButtonGroup>
    </>
  )
}

export default EffectFunc

クラスコンポーネントの場合

副作用は ReactがDOMを更新したあとに起こすようにしたいので、componentDidMountcomponentDidUpdateに記載します。するとReactDOMに変更を加えた後に、document.titleを更新しています。

react.js
  componentDidMount(){
    document.title =`${this.state.count}回クリックされました`
  }

  componentDidUpdate(){
    document.title =`${this.state.count}回クリックされました`
  }

関数コンポーネントでuseEffectを使った場合

デフォルトでは、useEffectは毎回のレンダー後に呼ばれます。

react.js
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title =`${count}回クリックされました`
  })

React公式サイトのstate とライフサイクルをもう一度読むと理解が進みました。
参考:React公式サイト state とライフサイクル

useEffectの第2引数に配列を渡して特定の値が変わったときだけ再レンダーさせる

useEffect()の第2引数に[count]を渡すと、countに変化があったときだけ再レンダーします。

react.js
import React, {useState, useEffect} from 'react'
import { makeStyles } from '@material-ui/core/styles';
import ButtonGroup from '@material-ui/core/ButtonGroup'
import Button from '@material-ui/core/Button'
import Input from '@material-ui/core/Input';

const useStyles = makeStyles((theme) => ({
  root: {
    '& > *': {
      margin: theme.spacing(1),
    },
  },
}));

const EffectFunc = () => {
  const classes = useStyles();
  const [count, setCount] = useState(0)
  const [name, setName] = useState({
    lastName: '',
    firstName: ''
  })
  useEffect(() => {
    document.title =`${count}回クリックされました`
  },[count])

  return (
    <>
      <p>{`${count}回クリックされました`}</p>
      <ButtonGroup color="primary" aria-label="outlined primary button group">
        <Button onClick={()=>setCount((prev) => prev + 1)}>
          ボタン
        </Button>
        <Button onClick={()=>setCount(0)}>
          リセット
        </Button>
      </ButtonGroup>
      <p>{`私の名前は${name.lastName} ${name.firstName}です`}</p>
      <form className={classes.root} noValidate autoComplete="off">
        <Input
          placeholder=""
          value={name.lastName}
          onChange={(e)=>{setName({...name,lastName: e.target.value})}}/>
        <Input
          placeholder=""
          value={name.firstName}
          onChange={(e)=>{setName({...name,firstName: e.target.value})}}/>
      </form>
    </>
  )
}

export default EffectFunc
useEffectの第2引数に[count]を取るとき
react.js
  useEffect(() => {
    document.title =`${count}回クリックされました`
    console.log(`再レンダーされました`)
  },[count])

nameが更新されても再レンダーされず、countが更新された場合だけ、document.titleが再レンダーされていることがわかります。

第2引数に[count]を取らないとき

useEffectはデフォルトで、副作用関数は初回のレンダー時および毎回の更新時に呼び出されます。

react.js
  useEffect(() => {
    document.title =`${count}回クリックされました`
    console.log(`再レンダーされました`)
  })

countが更新された場合だけだけでなく、nameが更新された場合にも、document.titleが再レンダーされていることがわかります。

第2引数にからの配列[]を取ったとき

レンダリングは初回のみで再レンダーされないので、document.titleは更新されません。

react.js
  useEffect(() => {
    document.title =`${count}回クリックされました`
    console.log(`再レンダーされました`)
  },[])

クリーンアップについて

クリーンアップとはイベントリスナの削除、タイマーのキャンセルなどのことです。
クリーンアップ関数をreturnすると、2度目以降のレンダリング時に前回の副作用を消してしまうことができます。

クラスコンポーネントの場合

componentWillUnmountは、クリーンアップ(addEventLitenerの削除、タイマーのキャンセルなど)に使用されます。componentDidMountに副作用を追加し、componentWillUnmountで副作用を削除します。

react.js
componentDidMount() {
  elm.addEventListener('click', () => {})
}

componentWillUnmount() {
  elm.removeEventListener('click', () => {})
}
関数コンポーネントの場合

上記に相当するhookは以下。「クリーンアップ関数」をreturnすることで、2度目以降のレンダリング時に前回の副作用を消してしまうことができます。

react.js
useEffect(() => {
   elm.addEventListener('click', () => {})

  // returned function will be called on component unmount 
  return () => {
     elm.addEventListener('click', () => {})
  }
}, [])

最後に

次回は useContext について書きたいと思います。

参考にさせていただいたサイト

https://reactjs.org/

seira
エイチームライフスタイルのフロントエンドデザイナ。 最近はReact, Rails, php, jQuery Sass, Photoshop, Figmaなどを触っています。
life-a-tm
人生のイベントや日常生活に密着した比較サイト、情報サイト等様々なウェブサービスを企画・開発・運営
https://life.a-tm.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away