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させる