React Hooks あれこれ

環境構築

npx create-react-app --scripts-version バージョン アプリ名

バージョン確認方法

npm info create-react-app

構築できたか確認(自動で立ち上がる)

yarn start

基本

import React, { useState } from 'react';
const [count, setCount] = useState(0)

常に2つの要素を返すため、Javascriptの分割代入を使用してそれぞれの要素を受け取る
1つ目の要素(count)は今回であれば0(useStateの状態)が返ってくる
2つ目の要素(setCount)は関数(function)
関数にも名前をつける(キャメルケース)

import React, { useState } from 'react';


const App = () => {
  const [count, setCount] = useState(0)

  const increment = () => setCount(count + 1)
  const decrement = () => setCount(count - 1)

  return (
    <>
      <div>count: {count}</div>
      <button onClick={increment}>+1</button>
      <button onClick={decrement}>-1</button>
    </>
  );
}

export default App;
<button onClick={increment}>+1</button>

onClickでボタンがクリックされたらイベント発火
今回であればincrement関数が呼び出される

 const increment = () => setCount(count + 1)

今回であれば、状態countを+1したい
このcountを変更させるには、setCountに値を与えることでcountの状態が変更される

setCountの引数に値ではなく、関数を渡すこともできる
関数に状態を変えさせることもできる
引数には現時点での状態を返す
その値をもとに状態を変更したい場合に使用する

import React, { useState } from 'react';

const App = () => {
  const [count, setCount] = useState(0)

  const increment = () => setCount(count + 1)
  const decrement = () => setCount(count - 1)

  const increment2 = () => setCount(previousCount => previousCount + 1)
  const decrement2 = () => setCount(previousCount => previousCount - 1)

  const reset = () => setCount(0)
  const dobule = () => setCount(count * 2)
  const divide3 = () => setCount(previousCount =>
    previousCount % 3 === 0 ? previousCount / 3 : previousCount
  )

  return (
    <>
      <div>count: {count}</div>
      <div>
        <button onClick={increment}>+1</button>
        <button onClick={decrement}>-1</button>
      </div>
      <div>
        <button onClick={increment2}>+1</button>
        <button onClick={decrement2}>-1</button>
      </div>
      <div>
        <button onClick={reset}>Reset</button>
        <button onClick={dobule}>×2</button>
        <button onClick={divide3}>3の倍数の時だけ3で割る</button>
      </div>
    </>
  );
}

export default App;

複数の状態管理

import React, { useState } from 'react';

const App = props => {
  const [name, setName] = useState(props.name)
  const [price, setPrice] = useState(props.price)

  const reset = () => {
    setPrice(props.price)
    setName(props.name)
  }

  return (
    <>
      <p>現在の{name}は、{price}円です。</p>
      <button onClick={() => setPrice(price + 1)}>+1</button>
      <button onClick={() => setPrice(price - 1)}>-1</button>
      <button onClick={reset}>Reset</button>
      <input value={name} onChange={e => setName(e.target.value)}/>
    </>
  );
}

App.defaultProps = {
  name: '',
  price: 1000
}

export default App;
<input value={name} onChange={e => setName(e.target.value)}/>

onChangeでイベントを拾う(e)
e.target.valueでinputに入力された文字列を拾う

複数の状態を1つのオブジェクトに統合

import React, { useState } from 'react';

const App = props => {
  const [state, setState] = useState(props)
  const { name, price } = state

  return (
    <>
      <p>現在の{name}は、{price}円です。</p>
      <button onClick={() => setState({...state, price: price + 1})}>+1</button>
      <button onClick={() => setState({...state, price: price - 1})}>-1</button>
      <button onClick={() => setState(props)}>Reset</button>
      <input value={name} onChange={e => setState({...state, name: e.target.value})}/>
    </>
  );
}

App.defaultProps = {
  name: '',
  price: 1000
}

export default App;

useEffect

// useEffectをimportする
import React, { useEffect, useState } from 'react';

// 第一引数に関数を引き取ることができる
// jsxのrenderingの後にuseEffectは実行される(Domのどこかの要素に変更があれば呼び出される)
useEffect(() => {
    console.log('This is like componentDidMount or componentDidUpdate.')
  })

// 最初のrenderingのみ呼び出すには第二引数に空の配列を持たす
  useEffect(() => {
    console.log('This is like componentDidMount')
  }, [])

// 特定のパラメータの描画時または変更時のみ呼び出す時(今回であればnameが描画された時または変更された時に呼び出す)
  useEffect(() => {
    console.log('This callback is for name only.')
  }, [name])

reducer

const events = (state = [], action) => {
  switch (action.type){
    case 'CREATE_EVENT':
      const event = { title: action.title, body: action.body }
      const length = state.length
      const id = length === 0 ? 1 : state[length -1].id + 1
      return [...state, { id, ...event }]
    case 'DELETE_EVENT':
    case 'DELETE_ALL_EVENTS':
      return []
    default:
      return state
  }
}

export default events
const events = (state = [], action) => {}

reducerは2つの引数を受け取る 1つ目はstate(前回の状態)を受け取る 2つ目はactionを受け取る stateは未定義の場合があるため、state = []で初期化しておく

switch (action.type){
    case 'CREATE_EVENT':
      // データを吸い上げる
      const event = { title: action.title, body: action.body }
      // stateの長さを把握する
      const length = state.length
      // stateの長さが0であれば1を返す、0でなければ最後のidに+1をして返す
      const id = length === 0 ? 1 : state[length -1].id + 1
      // stateの最後の要素にeventデータを格納する
      return [...state, { id, ...event }]
    case 'DELETE_EVENT':
    case 'DELETE_ALL_EVENTS':
      return []
    default:
      return state
}

actionは常にtypeという属性が渡ってくる 今回であれば、typeは作成する場合、削除される場合、そういったtype以外の場合でswitchさせる