react新特性hooks
7770 ワード
react hooksは関数domに使用できますが、関数はclassのようにstateを保存できないので、hooksの特性でstateの状態を保存できます.
1.useStateとuseEffect
useStateは初期値を受け入れ、setStateと同様に名前を付ける値を返します.
useEffectはcomponentDidMountに相当し、returnの部分はcomponentWillUnmountに相当するが、少し異なり、この方法では最初のパラメータが関数であり、2番目のパラメータが1つの配列であることを受け入れ、どのuseStateの値が変化した場合、このuseEffectの内容が実行されるかを記入する.[]を入力すると、ページがロードされ、ページから離れるたびに実行されます.ここでcountが渡されると、countが変化するたびにuseEffectのコードが実行されます.ここでのsetCount(c=>c+1)はsetCount(count+1)にならないほうがいいです.空の配列を埋め込むときはuseEffectが1回しか実行されないので、そのときのcountはそのときの関数の中のcountによって何かを決定します.これは閉鎖トラップを引き起こす.だから最善の方法は、関数を使用してcountを入力し、新しいcountを返すことです.
2.useReducer
useReducerはuseStateに似ており、オブジェクトなどを変更すると、useReducerは問題を簡単にすることができます.useReducerは、変更が必要なときに返されるstateの関数を処理する方法を受け入れ、2番目は初期値です.初期値とdispacthメソッドを返します.そして、変更時にdispatch()を呼び出して変更する必要がある状態と数値を入力するだけでよい.countReducerによって処理され、新しいcountが返されます.
3.uselayoutEffect
これはuseEffectと少し似ていますが、これはDomがまだレンダリングが完了していないときに実行され、useEffectはレンダリング後に実行されます.通常、いくつかの変数またはアニメーションを変更するには、レンダリング後に実行する必要がありますので、これはあまり使用されません.
4.useContext
グローバルで変数を定義するのと同じです.祖先コンポーネントと子孫コンポーネント(複数の階層を隔てたコンポーネント)の値伝達を容易にします.まずReact.CreateContext()を使用して、コンポーネントのエクスポートにカプセル化する必要があります.
次に、親コンポーネントにコンポーネントを導入します.提供されるProviderコンポーネントを使用して、サブコンポーネントをラップします.value値はサブコンポーネントに渡す必要がある値です.ここのvalueはthisを使うことができます.state.xxxの代わりに、変更が発生すると、サブコンポーネントが取得した値も変更されます.
サブコンポーネントではuseContext(context component)で取得できますが、functional componentでなければエラーが発生しないことに注意してください.useContextで取得した値は、上に包まれたvalueの値です.
5.useRef
関数コンポーネントにはrefが存在しないためです.関数コンポーネントにrefを持つ必要がある場合はuseRefを使用する必要があります.使い方も簡単で、useRef()は取得したいdomに置くだけでrefを返します.
6.useMeme,useCallback
主にパフォーマンスの最適化に使用されます.一部のコンポーネントが更新されていない場合は、更新操作を必要とせずに、この2つを使用できます.
まずコードを変更して、Childの関数コンポーネントを追加しました.Childでは2つのパラメータを受け入れます.1つはbuttonイベントで、countの値を変更します.1つはcountの値を表示し、inputはnameの値を変更します.そしてChildでコンソールをして、Childが更新するたびの時点を記録します.
input入力が変更されるたびにchild renderが印刷されることが分かった.これは私たちが望んでいるものではありませんcountは変わっていないからです.Childコンポーネントは変更する必要はありません.この時、useMemoとmemoを使う必要があります.memoはclassのshouldComponentUpdateに似ており、関数コンポーネント自体に包むことができます.このコンポーネントはonButtonClickとconfigに完全に依存するため、この2つの数値が変化しない限り、Childコンポーネントは変化しない.
しかし、このように書き終わるとChildが変化することに気づきます.これはinputがnameを変化させ、nameの変化がmyCountコンポーネントを変化させるためです.myCountが変わるとconfigが再宣言されます.参照先が変更されるので、Childは再レンダリングされます.この時はuseMemoを使う必要があります.useMemoはconfigが変更されたかどうかを判断し、新しいオブジェクトを返すかどうかを判断します.このときconfigの声明を修正します.
1番目のパラメータはメソッドで、1つの値を返し、2番目のパラメータはuseEffectと同様に、その値に基づいて新しい値を返す必要があるかどうかを判断します.しかし、この時はまだだめで、inputを入力したとき、Childはレンダリングされました.これはonButtonClick={()=>dispatchCount({type:'add'})}が匿名関数として渡され、myCountが更新されるたびにアドレスが変わるためです.この場合、useMemoで関数を返すか、useCallbackで関数を返すことができます.2番目のパラメータも依存項目であり,ある値に基づいて更新するか否かを判断する.
useMemoを使用する場合は、関数を返すために複数のレイヤをラップする必要があります.
これよりinput値が変化するとChildは再レンダリングされず、countの値が変化する場合にのみ再レンダリングされ、Childのパフォーマンスの最適化が完了します.
7.閉包トラップ
関数コンポーネントであるため、閉パケットが発生しやすく、ある値を取得するためにsettimeoutを使用して遅延呼び出しを行った場合、その値は遅延時に変化したが、settimeoutが取得したのは実際には変化しなかった当時の値である.
クリック遅延後、さらに2秒以内にbuttonを2回クリックすると、このときポップアップされる値は2であるはずですが、閉パッケージの関係で弾き出されるのは0です.私たちがclassを使っている間は、thisを通っていたからです.state.countが取得するので、この問題は発生しません.しかし、関数では、現実と合わないことが起こりやすい.この場合はuseRefで解決できる.useRefは同じオブジェクトを返すため、ref.currentに値をマウントすることで最新の値を取得できます.この場合、次のような形式に変更できます.
1.useStateとuseEffect
useStateは初期値を受け入れ、setStateと同様に名前を付ける値を返します.
useEffectはcomponentDidMountに相当し、returnの部分はcomponentWillUnmountに相当するが、少し異なり、この方法では最初のパラメータが関数であり、2番目のパラメータが1つの配列であることを受け入れ、どのuseStateの値が変化した場合、このuseEffectの内容が実行されるかを記入する.[]を入力すると、ページがロードされ、ページから離れるたびに実行されます.ここでcountが渡されると、countが変化するたびにuseEffectのコードが実行されます.ここでのsetCount(c=>c+1)はsetCount(count+1)にならないほうがいいです.空の配列を埋め込むときはuseEffectが1回しか実行されないので、そのときのcountはそのときの関数の中のcountによって何かを決定します.これは閉鎖トラップを引き起こす.だから最善の方法は、関数を使用してcountを入力し、新しいcountを返すことです.
import React, { useState, useEffect } from 'react'
function myTimer() {
const [count, setCount] = useState(0)
useEffect(() => {
console.log(count)
const intenval = setInterval(() => {
setCount(c => c + 1)
}, 1000)
return () => clearInterval(intenval)
}, [])
return {count}
}
export default myTimer
2.useReducer
useReducerはuseStateに似ており、オブジェクトなどを変更すると、useReducerは問題を簡単にすることができます.useReducerは、変更が必要なときに返されるstateの関数を処理する方法を受け入れ、2番目は初期値です.初期値とdispacthメソッドを返します.そして、変更時にdispatch()を呼び出して変更する必要がある状態と数値を入力するだけでよい.countReducerによって処理され、新しいcountが返されます.
import React, { useState, useReducer, useEffect } from 'react'
//
function countReducer(state, action) {
switch (action.type) {
case 'add':
return state + 1
case 'minus':
return state - 1
default:
return state
}
}
function myTimer() {
// const [count, setCount] = useState(0)
const [count, dispatchCount] = useReducer(countReducer, 0)
useEffect(() => {
const intenval = setInterval(() => {
// setCount(c=>c+1)
dispatchCount({ type: 'add' })
}, 1000)
return () => {
console.log('didmount')
return clearInterval(intenval)
}
}, [])
return {count}
}
export default myTimer
3.uselayoutEffect
これはuseEffectと少し似ていますが、これはDomがまだレンダリングが完了していないときに実行され、useEffectはレンダリング後に実行されます.通常、いくつかの変数またはアニメーションを変更するには、レンダリング後に実行する必要がありますので、これはあまり使用されません.
4.useContext
グローバルで変数を定義するのと同じです.祖先コンポーネントと子孫コンポーネント(複数の階層を隔てたコンポーネント)の値伝達を容易にします.まずReact.CreateContext()を使用して、コンポーネントのエクスポートにカプセル化する必要があります.
import React from 'react'
export default React.createContext('')
次に、親コンポーネントにコンポーネントを導入します.提供されるProviderコンポーネントを使用して、サブコンポーネントをラップします.value値はサブコンポーネントに渡す必要がある値です.ここのvalueはthisを使うことができます.state.xxxの代わりに、変更が発生すると、サブコンポーネントが取得した値も変更されます.
サブコンポーネントではuseContext(context component)で取得できますが、functional componentでなければエラーが発生しないことに注意してください.useContextで取得した値は、上に包まれたvalueの値です.
import React, { useState, useReducer, useEffect, useContext } from 'react'
import MyContext from '../lib/my-context'
function myTimer() {
const context = useContext(MyContext)
const [count, dispatchCount] = useReducer(countReducer, 0)
useEffect(() => {
const intenval = setInterval(() => {
// setCount(c=>c+1)
dispatchCount({ type: 'add' })
}, 1000)
return () => {
console.log('didmount')
return clearInterval(intenval)
}
}, [])
return (
{count}
{context}
)
}
5.useRef
関数コンポーネントにはrefが存在しないためです.関数コンポーネントにrefを持つ必要がある場合はuseRefを使用する必要があります.使い方も簡単で、useRef()は取得したいdomに置くだけでrefを返します.
import React, {useState, useReducer, useEffect, useContext, useRef} from 'react'
function myTimer() {
const [count, dispatchCount] = useReducer(countReducer, 0)
const context = useContext(MyContext)
const spanRef = useRef()
console.log(spanRef)
return (
{count}
{context}
)
}
6.useMeme,useCallback
主にパフォーマンスの最適化に使用されます.一部のコンポーネントが更新されていない場合は、更新操作を必要とせずに、この2つを使用できます.
まずコードを変更して、Childの関数コンポーネントを追加しました.Childでは2つのパラメータを受け入れます.1つはbuttonイベントで、countの値を変更します.1つはcountの値を表示し、inputはnameの値を変更します.そしてChildでコンソールをして、Childが更新するたびの時点を記録します.
function myCount() {
const [name, setName] = useState('yiki')
const [count, dispatchCount] = useReducer(countReducer, 0)
const config = {
text: `count is ${count}`,
color: count > 3 ? 'red' : 'blue'
}
return (
setName(e.target.value)}>
dispatchCount({ type: 'add' })}
config={config}
>
)
}
function Child({ onButtonClick, config }) {
console.log('child render')
return (
)
}
export default myTimer
input入力が変更されるたびにchild renderが印刷されることが分かった.これは私たちが望んでいるものではありませんcountは変わっていないからです.Childコンポーネントは変更する必要はありません.この時、useMemoとmemoを使う必要があります.memoはclassのshouldComponentUpdateに似ており、関数コンポーネント自体に包むことができます.このコンポーネントはonButtonClickとconfigに完全に依存するため、この2つの数値が変化しない限り、Childコンポーネントは変化しない.
import { memo } from 'react'
const Child = memo(function Child({ onButtonClick, config }) {
console.log('child render')
return (
)
})
しかし、このように書き終わるとChildが変化することに気づきます.これはinputがnameを変化させ、nameの変化がmyCountコンポーネントを変化させるためです.myCountが変わるとconfigが再宣言されます.参照先が変更されるので、Childは再レンダリングされます.この時はuseMemoを使う必要があります.useMemoはconfigが変更されたかどうかを判断し、新しいオブジェクトを返すかどうかを判断します.このときconfigの声明を修正します.
import { useMemo } from 'react'
const config = useMemo(
() => ({
text: `count is ${count}`,
color: count > 3 ? 'red' : 'blue'
}),
[count]
)
1番目のパラメータはメソッドで、1つの値を返し、2番目のパラメータはuseEffectと同様に、その値に基づいて新しい値を返す必要があるかどうかを判断します.しかし、この時はまだだめで、inputを入力したとき、Childはレンダリングされました.これはonButtonClick={()=>dispatchCount({type:'add'})}が匿名関数として渡され、myCountが更新されるたびにアドレスが変わるためです.この場合、useMemoで関数を返すか、useCallbackで関数を返すことができます.2番目のパラメータも依存項目であり,ある値に基づいて更新するか否かを判断する.
import { useCallback } from 'react'
const handleButtonClick = useCallback(
() => dispatchCount({ type: 'add' }),
[]
)
useMemoを使用する場合は、関数を返すために複数のレイヤをラップする必要があります.
const handleButtonClick = useMemo(
() => () => dispatchCount({ type: 'add' }),
[]
)
これよりinput値が変化するとChildは再レンダリングされず、countの値が変化する場合にのみ再レンダリングされ、Childのパフォーマンスの最適化が完了します.
7.閉包トラップ
関数コンポーネントであるため、閉パケットが発生しやすく、ある値を取得するためにsettimeoutを使用して遅延呼び出しを行った場合、その値は遅延時に変化したが、settimeoutが取得したのは実際には変化しなかった当時の値である.
function MyCount(){
const [count,setCount] = useState(0)
return <>
>
}
クリック遅延後、さらに2秒以内にbuttonを2回クリックすると、このときポップアップされる値は2であるはずですが、閉パッケージの関係で弾き出されるのは0です.私たちがclassを使っている間は、thisを通っていたからです.state.countが取得するので、この問題は発生しません.しかし、関数では、現実と合わないことが起こりやすい.この場合はuseRefで解決できる.useRefは同じオブジェクトを返すため、ref.currentに値をマウントすることで最新の値を取得できます.この場合、次のような形式に変更できます.
function MyCount(){
const [count,setCount] = useState(0)
const countRef = useRef()
countRef.current = count
return <>
>
}