Reactフックの使用を開始し、クラスコンポーネントを比較して、useStateとuseEffectを学習します[実践、要約]

ブロガーの経験はまだ浅いです、何か間違いがあれば私を訂正してください

1つ:useState

1.使用方法

function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];

上記のフック定義のソースコードからわかるように、useStateフック関数のパラメーターは初期値(または呼び出し後に初期値を取得する関数)で渡され、戻り値は状態の読み取りおよび書き込み操作のために外部に返されます(配列の形式で)基本的な使用例は次のとおりです。

const [state, setState] = useState(initialState);

2.ユースケース

ご存知のとおり、クラスコンポーネントはステートフルコンポーネントとも呼ばれ、状態を管理する機能があります。フック関数が表示される前は、関数コンポーネントはステートレスコンポーネントとも呼ばれ、状態を管理する機能はありません。フック関数が表示されるまで、関数コンポーネントには状態を管理する機能があります。以下は、クラスコンポーネントと関数コンポーネント(useStateを使用)間の状態管理の実装の違いのリストです。これらの2つの方法で、状態の初期化状態の読み取りおよび書き込み操作に注意しください

クラスコンポーネント管理ステータス
import React from "react";

export default class ClassComp extends React.Component {
    
    
  constructor(props) {
    
    
    super(props);
    this.state = {
    
    
      count: 0
    };
  }

  render() {
    
    
    return (
      <div>
        <p>You clicked {
    
    this.state.count} times (classComp)</p>
        <button onClick={
    
    () => this.setState({
    
     count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}
機能コンポーネント管理状態(useState)
import React, {
    
     useState } from "react";

export default function FuncComp() {
    
    
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {
    
    count} times (FuncComp)</p>
      <button onClick={
    
    () => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

3.使用法の詳細

(1)遅延初期状態[パフォーマンスの最適化:useState(fn)などのfnによって計算されたinitialState]

initialStateパラメーターは、コンポーネントの初期レンダリングでのみ機能し、後続のレンダリングでは無視されます。複雑な計算で初期状態を取得する必要がある場合は、関数を渡して計算し、関数の初期状態を返すことができます。この関数は、初期レンダリング中にのみ呼び出されます。

  • 望ましくない方法1.InitialStateはレンダリングごとに計算されるため、パフォーマンスが低下します。
const initialState = someExpensiveComputation(props);
const [state, setState] = useState(initialState);
  • 推奨される方法2:関数を渡すことにより、初期値を計算するための関数が1回だけ呼び出されます。
const [state, setState] = useState(() => {
    
    
  const initialState = someExpensiveComputation(props);
  return initialState;
});
(2)機能の更新[コーディングの最適化:setXxx(fn)などのfnによって計算されたupdateState]

以前の状態を使用して新しい状態を計算する必要がある場合は、関数をsetStateに渡すことができます。この関数は前の状態を受け取り、更新された値を返します。次のカウンタコンポーネントの例は、setStateの2つの使用法を示しています。

function Counter({
    
    initialCount}) {
    
    
  const [count, setCount] = useState(initialCount);
  return (
    <>
      Count: {
    
    count}
      <button onClick={
    
    () => setCount(initialCount)}>Reset</button>
      <button onClick={
    
    () => setCount(prevCount => prevCount - 1)}>-</button>
      <button onClick={
    
    () => setCount(prevCount => prevCount + 1)}>+</button>
    </>
  );
}
(3)状態の更新をスキップする[疑問を解決する:同じ値の更新が状態の変更と見なされるかどうか]

State Hookの更新関数を呼び出して現在の状態を渡すと、Reactは子コンポーネントのレンダリングとエフェクトの実行をスキップします(ReactはObject.is比較アルゴリズムを使用して状態を比較します。)

  • object.isの比較アルゴリズムは次のとおりです。以下のことにより、アドレス判断ルールの基本的な使用法を使用して判断できると最初に結論付けることができます
Object.is('foo', 'foo');     // true
Object.is(window, window);   // true

Object.is('foo', 'bar');     // false
Object.is([], []);           // false

var foo = {
    
     a: 1 };
var bar = {
    
     a: 1 };
Object.is(foo, foo);         // true
Object.is(foo, bar);         // false

Object.is(null, null);       // true

// 特例
Object.is(0, -0);            // false
Object.is(0, +0);            // true
Object.is(-0, -0);           // true
Object.is(NaN, 0/0);         // true

2:useEffect

1.使用方法

 function useEffect(effect: EffectCallback, deps?: DependencyList): void;

上記のフック定義のソースコードからわかるように、 useEffectフック関数のパラメーター1は副作用コールバック関数で渡され、パラメーター2は副作用の依存関係配列(オプション)渡され、戻り値はありません。基本的な使用例は次のとおりです。

  // componentDidMount or componentDidUpdate && count state change
  useEffect(() => {
    
    
    console.log(count)
  },[count])

2.ユースケース

クラスコンポーネントの副作用
import React from "react";

export default class ClassComp extends React.Component {
    
    
  constructor(props) {
    
    
    super(props)
    this.state = {
    
    
      count: 0
    };
  }

  componentDidMount() {
    
    
    console.log('class', 'componentDidMount')
  }

  componentWillUpdate(nextProps, nextState) {
    
    
    console.log('class', 'componentWillUpdate')
    if(this.state.count !== nextState.count)console.log(this.state.count)
  }

  componentDidUpdate(prevProps, prevState) {
    
    
    console.log('class', 'componentDidUpdate')
    if(this.state.count !== prevState.count)console.log(this.state.count)
  }

  componentWillUnmount() {
    
    
    console.log('class', 'componentWillUnmount')
  }
  render() {
    
    
    return (
      <div>
        <p>You clicked {
    
    this.state.count} times (classComp)</p>
        <button onClick={
    
    () => this.setState({
    
     count: this.state.count + 1 })}>
          Click me
      </button>
      </div>
    );
  }
}
機能コンポーネントの副作用(useEffect)
import React, {
    
     useState, useEffect } from "react";

export default function FuncComp() {
    
    
  const [count, setCount] = useState(0)

  // 等同于:componentDidMount
  useEffect(() => {
    
    
    console.log('function', 'componentDidMount')
  }, [])

  // 等同于:componentDidMount or componentDidUpdate
  useEffect(() => {
    
    
    console.log('function', 'componentDidMount or componentDidUpdate')
  })

  // 等同于:(componentDidMount or componentDidUpdate) && count state change
  useEffect(() => {
    
    
    console.log('function', 'componentDidUpdate console newCount', count)
  }, [count])

  // 等同于:componentWillUpdate or componentWillUnmount
  useEffect(() => {
    
    
    return () => {
    
    
      console.log('function', 'componentWillUpdate or componentWillUnmount')
    }
  })

  // 等同于:(componentWillUpdate or componentWillUnmount ) && count state change
  useEffect(() => {
    
    
    return () => {
    
    
      console.log('function', 'componentWillUpdate or componentWillUnmount console preCount', count)
    }
  }, [count])

  // 等同于:componentWillUnmount
  // useEffect(() => {
    
    
  //   return () => {
    
    
  //     console.log('function', 'componentWillUnmount')
  //   }
  // },[])

  // 等同于:(componentDidMount or componentDidUpdate) and (componentWillUpdate or componentWillUnmount)
  // useEffect(() => {
    
    
  //   console.log('function', 'componentDidMount or componentDidUpdate')
  //   return () => {
    
    
  //     console.log('function', 'componentWillUpdate or componentWillUnmount')
  //   }
  // })
  return (
    <div>
      <p>You clicked {
    
    count} times (FuncComp)</p>
      <button onClick={
    
    () => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
運用結果

  • ここに写真の説明を挿入
    コンポーネントがマウントされた後、上記の実行結果からマウントを確認できます。クラスコンポーネントのcomponentDidMountライフサイクルメソッドのみが実行され、関数コンポーネントのすべてのuseEffect副作用ロジックが実行されます(最後の2つのuseEffectsのみが登録されているため、コンソールは3つだけです)。ロジックを更新およびアンインストールする前)。

  • ここに写真の説明を挿入
    上記の実行結果から更新を確認できます。コンポーネントが更新された後、クラスコンポーネントのcomponentWillUpdateおよびcomponentDidUpdateライフサイクルメソッドが実行され、関数コンポーネントのuseEffectロジックのすべての副作用は、空の最初の登録済み依存関係配列を除いてすべて副作用です。ロジックが実行されます(実行されるアレイによっては副作用はありません)。
  • アンロード
    ここに写真の説明を挿入
    上記の実行結果から、コンポーネントがアンロードされた後、クラスコンポーネントのcomponentWillUnMountライフサイクルメソッドが実行され、アンインストールロジックが登録されている場合、関数コンポーネントのuseEffectのすべての副作用ロジックが実行されることがわかります。

3.使用法の詳細

(1)使用のトリガー条件効果副作用ロジック

デフォルトでは、エフェクトはレンダリングの各ラウンドの後に実行されますが、依存関係の配列を渡すことによって特定の値が変更された場合にのみ実行できます。

(2)useEffect副作用ロジックがトリガーされた後の実行時間

componentDidMountやcomponentDidUpdateとは異なり、ブラウザがレイアウトと描画を完了した後、useEffectに渡された関数はdelayedと呼ばれます。

(3)useEffect副作用ロジックのクリア[メモリリークを防ぐため]

通常、コンポーネントをアンインストールするときは、エフェクトによって作成されたサブスクリプションやタイマーIDなどのリソースをクリアする必要があります(上記の例の6番目のuseEffectのように)。メモリリークを防ぐために、コンポーネントがアンロードされる前にクリーンアップ機能が実行されます。
さらに、コンポーネントが複数回(通常)レンダリングされる場合、次のエフェクトが実行される前に前のエフェクトがクリアされます(上記の例の4番目と5番目のuseEffectのように)。

4.残された疑問

上記の例から、useEffectフックは、クラスコンポーネント内のwillMountとunMountの2つのライフサイクルの個別の実現をシミュレートでき、willMountとDidUpdateの組み合わせ、unMountとwillUpdateの組み合わせ、およびwillMountとDidUpdateをシミュレートできることがわかります。 、UnMount、willUpdateの4つの組み合わせ。しかし、問題があります。別のDidUpdateまたはWillUpdateライフサイクルメソッドをどのようにシミュレートできますか?実際の開発では、そのような要望に応え、適切な解決策が見つからなかったため、Wanziの実装を惜しまず、更新フェーズでしか利用できない特定のフラグ状態を判断して、マウント状態を排除しました。副作用ロジックは、DidUpdate中にのみ実行され、DidMount中には実行されません。人を見るより良い方法があれば、私に知らせてください、ありがとう!

おすすめ

転載: blog.csdn.net/jw2268136570/article/details/108766428