React Hook
React Hooks にはいくつかあります。
- useState
- useEffect / useLayoutEffect
- useContent
- useReducer
- useMemo / useCallBack
- useRef / useImperativeHandle
useState
使い方:
const [n,setN] = React.useState(0)
const [n,setN] = React.useState( {name : 'hht'} )
上記のコードは、レンダリングされるたびに初期値の片側を計算するもので、より効率的にするために関数として書くことができます。
const [n, setN] = React.useState( () => 0 )
setNを使うたびに新しいスコープが作成されるからです。
ですから、古いnと新しいnを混同しないように、setNを使うときは、関数の形で書くことをお勧めします。
const add = () => {
setN( i => i + 1 )
}
useReducer
useReducerの使い方:
- 変数の初期化
- 全オペレーションの作成
- コンポーネントへの読み書きインターフェースの導入
- 書き込みインターフェイスの呼び出し
const inital = {n: 0, i: 1}
const reducer = (state, action) => {
if (action.type === 'add') {
return {...inital, n: action.n}
} else if (action.type === 'multi') {
return {...inital, n: action.n}
}
}
const App = () => {
const [state, dispatch] = React.useReducer(reducer, inital)
const add = () => {
dispatch({type: 'add', n: state.n + 1})
}
return (
<div>
number: n : {state.n} , i : {state.i}
<button onClick={add}>n+1</button>
</div>
)
}
使用コンテキスト
ローカルなグローバルスコープは useContext で作成できます。
useContext内のコンポーネントは、useContext内の値から自由に呼び出すことができます。
const c = React.createContext(null)
const App = () => {
const [n,setN] = React.useState(0)
const add = () => {
setN( i => i +1)
}
return (
<c.Provider value={ {n,add} }>
<Child />
</c.Provider>
)
}
const Child = () => {
const {n,add} = React.useContext(c)
return (
<div>
n : {n}
<button onClick={add}>+1</button>
</div>
)
}
useEffect / useLayoutEffect
クラス・コンポーネントのライフ・サイクルは、Effect を使用してシミュレートできます。
useEffectとは異なり、useLayoutEffectはDOM ===> appearanceの途中で呼び出されます。
つまり、useLayoutEffectの呼び出しは、実際にはuseEffectの呼び出しの前に行われます。
memo/useMemo / useCallbcak
他のコンポーネントを含むコンポーネントの場合
外側のコンポーネントが更新されると、内側のコンポーネントも再レンダリングされます。
useMemoは、内部コンポーネントを再レンダリングする必要がない場合はレンダリングしないことで、この問題を解決するために使用されます。
const App = () => {
const [n, setN] = React.useState(0)
const add = () => {
setN(i => i + 1)
}
return (
<div>
{n}
<button onClick={add}> +1</button>
<Child2/>
</div>
)
}
const Child = () => {
console.log('hi')
return (
<div>Child</div>
)
}
const Child2 = React.memo(Child)
上のコードの最後の行はメモを使っているので、Childがランダムにレンダリングされることはもうありませんが、Childにリスナー関数を渡すと、レンダリングが行われるたびに古いオブジェクトと新しいオブジェクトが====にならないので
この時点で、useMemoを使用する必要があります、useMemo(キャッシュ値)は、2番目のパラメータにする必要があります、依存関係を宣言することです、どの変数が子をレンダリングする前に変更されます。
const xxx = React.useMemo(() => {
return () => {}
}, [])
関数の中で関数を返す必要がある上記のコードは、useCallback(キャッシュ関数) を使用することで簡略化できます。
const xxx = React.useCallback( () => {}, [] )
useRef
React.useRefを使用することで、useStateと同様の機能を実現でき、useStateのように変数が更新されるたびに新しい変数が生成されることはありません。
React.useRefを実装して、DOMを取得することもできます。
- 同じ変数の更新
const App = () => {
const divRef = React.useRef(100)
const [_n, _setN] = React.useState(null)
const add = () => {
divRef.current += 1
_setN(divRef.current)
}
return (
<div>
{divRef.current}
<button onClick={add}>+1</button>
</div>
)
}
useRef は変数を生成するので、毎回レンダリングし直しても、異なる divRef は同じアドレスを指します。
また、refを更新してもビューは更新されないので、ビューの更新を補助するuseStateが必要です。
- DOMの取得
クラスコンポーネントでは、React.useRefを介して他のコンポーネントにref値を渡し、親コンポーネントでその値を取得することができます。
class App extends React.PureComponent {
render() {
const divRef = React.createRef()
return (
<div>
<Child ref1={divRef}/>
<button
onClick={() => {
console.log(divRef.current)
}}>log
</button>
</div>
);
}
}
class Child extends React.PureComponent {
constructor(props) {
super(props);
}
render() {
return (
<div ref={this.props.ref1}>123</div>
)
}
}
ファンクションコンポーネントでは、上記のメソッドは機能しません。
const App = () => {
const divRef = React.useRef(null)
return (
<div>
<Child2 ref1={divRef}/>
<button
onClick={() => {
console.log(divRef.current)
}}>log
</button>
</div>
)
}
const Child = (props, ref1) => {
return (
<div ref={props.ref1}>child</div>
)
}
const Child2 = React.forwardRef(Child)