React のクラスからフックへの移行

React のクラスからフックへの移行

Reactフック

序文

これまでの 3 年間、私はクラスを使用してフロントエンドの機能ページを書いてきました。実際、フックについてはしばらく前から触れてきました。私が初めてこれに出会ったのは、electron+react プロジェクトに関するコースを視聴していたときでした。当時はelectronを主に見ていたため、hooksについては特に注目していませんでした。また、私が長年クラスに慣れ親しんできたせいもあるかもしれませんが、当時はフックの関数型の記述スタイルに多少抵抗がありました。しかし、業界でフックが好意的に評価されていたため、フックを使用してプロジェクトを開始したいと思ったこともありました。しかし、当時のプロジェクト サイクルと既存のテクノロジー スタックのせいで、それを実践する機会がありませんでした。

最近、新しいプロジェクトに react hooks+ts を使用しているためです。したがって、フックの使用を開始する必要があります。実際、機能開発に関する限り、他のものをコピーするだけでは何も問題はありません。しかし、フックについて体系的かつ深く理解されていないため、多くの場合、なぜこのようにフックを使用するのかが明確ではありません。そこで最近、「React Hooks Core Principles and Practice」を見つけて勉強しました。

フックの使用と、使用法と理由のレベルでフックを使用する理由を再検討します。機能的なライティングの利点についてさらに検討します。実のところ、ある程度、私は表面をなぞっただけです。ここでは、この期間に私が学んだことを記録しているだけです。

なぜフックなのか?

Hooks の大きな特徴は、ビジネス ロジックを再利用できることです。これはフックにおいて特に顕著です。例えば、通常のクラスでウィンドウサイズの変化を監視したい場合、実装後にコンポーネント内に監視イベントを追加する必要があります。しかし、このウィンドウサイズ監視機能が別の場所でも必要になった場合、このロジックコードは再利用できず、そのコンポーネント内でしか書き換えることができません。ただし、フックでは、監視ロジック コードのこの部分をフック モードでカプセル化し、論理的な再利用を完全に実現できます。

クラス用

  • React のキャリアとして Class を使用する場合:
  • コンポーネントは相互に継承せず、クラス継承機能も利用しません。UI は状態駆動型であり、すべてのメソッドは内部的に呼び出されるか、ライフサイクル メソッドとして自動的に呼び出されます。クラスのインスタンスメソッドを呼び出す機能は使用されていない

機能について

React の中核の 1 つは、State データから View レベルへのバインディングを実現することです。関数を使用するのは、実際には、状態からビューへのマッピングの問題を解決するより良い方法です。ただし、React のキャリアとして関数を使用すると、関数内の状態の保存ライフサイクル メソッドという 2 つの問題が発生します。

  • フックは、外部データを関数の実行にバインドすることで、上記の 2 つの問題をどのように解決しますか。データが変更されたときに関数が自動的に再実行されるようにします。このように、UI の表示に影響を与える外部データは、このメカニズムを通じて React の関数コンポーネントにバインドできます。
  • フックの理解: 変更される可能性のあるデータ ソースまたはイベント ソースにターゲット結果をフックします。フックされたデータまたはイベントが変更されると、ターゲット結果を生成するコードが再実行され、更新された結果が生成されます。

図: 関数コンポーネント自体などの実行プロセス (実行) は、従来の状態、URL、またはウィンドウのサイズにバインド (フック) できます。このように、状態、URL、またはウィンドウ サイズが変更されると、関数が再実行され、更新された結果が生成されます。

クラスとフック

  • クラス コンポーネントと比較すると、関数コンポーネントは State => View の論理関係に沿っているため、React コンポーネントの実行を表現するのに適しています。しかし、ステータス、ライフサイクル、その他のメカニズムが欠如しているため、その機能は常に限られていました。 Hooksは、Reactキャリアとして関数コンポーネントの状態ライフサイクルの制限された問題を解決し、その機能を最大限に活用できるようにします。
  • フックにフックされたオブジェクトは、独立したデータソースまたは別のフックの実行結果である可能性があり、これにより、フックの最大の利点であるロジックの再利用が実現します。
  • ロジックの再利用を簡素化
    • クラスメソッドの場合: ロジックの再利用のために高次コンポーネントの設計パターンを使用します。たとえば、ウィンドウのサイズ変更機能を再利用したい場合は、UI のない外部コンポーネントを定義し、関連するサイズ変更ロジックの定義を記述してから、データ結果を属性の形式で子コンポーネントに渡す必要があります。コンポーネントがこのロジックを再利用したい場合は、このコンポーネントでラップして返す必要があります。全体として、外部状態を渡すには、UI のない外部コンポーネントを定義する必要があり、このコンポーネントは再利用可能なロジックをカプセル化するためだけのものです。 **頻繁に使用すると、高レベルコンポーネントごとにノードのレイヤーが追加され、デバッグなどに大きな負担がかかります。
//クラス内の高レベルコンポーネントは resize メソッドの再利用を実装します //1. 高レベルコンポーネントの宣言 const withWindowSize = Component => {
  // ウィンドウサイズを監視するロジックのみを含む高レベルコンポーネント WrappedComponent を生成します。class WrappedComponent extends React.PureComponent {
    コンストラクタ(props) {
      スーパー(小道具);
      この状態 = {
        サイズ: this.getSize()
      };
    }
    コンポーネントマウント() {
      window.addEventListener("サイズ変更", this.handleResize); 
    }
    コンポーネントのマウントを解除します(){
      window.removeEventListener("サイズ変更", this.handleResize);
    }
    取得サイズ() {
      window.innerWidth > 1000 ? "large" : "small" を返します。
    }
    ハンドルサイズ変更 = () => {
      現在のサイズを取得します。
      this.setState({
        サイズ: this.getSize()
      });
    }
    与える() {
      // ウィンドウ サイズを実際のビジネス ロジック コンポーネントに渡します。 return <Component size={this.state.size} />;
    }
  }
  WrappedComponent を返します。
};
//2. コンポーネント MyComponent は高階コンポーネントの resize 関数を使用します。クラス MyComponent は React.Component を拡張します{
  与える() {
    const { size } = this.props;
    if (size === "small") return <SmallComponent />;
    それ以外の場合は <LargeComponent /> を返します。
  }
}
// withWindowSize を使用して高次コンポーネントを生成し、サイズ属性を生成して実際のビジネス コンポーネントに渡します。export default withWindowSize(MyComponent); 
  • Hooks メソッドの場合: resize が実装されている場合、ウィンドウ サイズは単なる外部データ状態になります。フックを使用してこれをカプセル化し、バインド可能なデータ ソースに変換するだけです。ウィンドウのサイズが変更されると、コンポーネントもコードを再レンダリングします。これにより、より簡潔で直感的になり、追加のコンポーネント ノードは生成されません。
//Hooksはhooksメソッドを使用してサイズ変更ロジックを再利用します //useWindowSizeフックを定義します
定数getSize = () => {
  window.innerWidth > 1000 ? "large" : "small" を返します。
}
定数useWindowSize = () => {
  const [size, setSize] = useState(getSize());
  使用効果(() => {
  定数ハンドラ = () => {
      サイズを設定する(サイズを取得する())
    };
    window.addEventListener('resize', ハンドラ);
    戻り値 () => {
      window.removeEventListener('resize', ハンドラー);
    };
  }, []);
  サイズを返します。
};
//関数コンポーネントでこのフックを使用する
constデモ = () => {
  定数サイズ = useWindowSize();
  if (size === "small") return <SmallComponent />;
  それ以外の場合は <LargeComponent /> を返します。
};
  • 関心の分離に役立ちます

フックは、同じビジネス ロジックのコードを可能な限り集約できます。クラス コンポーネントでは、同じビジネス ロジック コードをクラス コンポーネントの異なるライフ サイクル メソッドに分散させる必要があります。

画像

図: 左側はクラス コンポーネント、右側はフックと組み合わせた関数コンポーネントです。青と黄色は異なるビジネス機能を表す

フックはコンポーネントの状態を保存し、ライフサイクルをどのように使用しますか?

React は、 useStateuseEffectuseCallbackuseMemouseRefuseContextなど、合計 10 個のHooksを提供します。

1. useState: 関数が状態を維持できるようにする

私たちが従うべき原則の 1 つは、次のような計算可能な値を状態に保存してはならないということです。

  • props から渡された値。場合によっては、props によって渡された値を直接使用できず、並べ替えなどの特定の計算を行った後に UI に表示する必要があります。したがって、必要なのは、結果を使用するたびに結果を再ソートするか、結果を直接状態に置くのではなく、何らかのキャッシュ メカニズムを使用することです。
  • URL から読み取られた値。たとえば、URL 内のパラメータを読み取って、それをコンポーネント状態の一部として使用する必要がある場合もあります。そうすれば、それを読み取って直接状態に置くのではなく、必要なときに毎回 URL から読み取ることができます。
  • クッキーとlocalStorageから読み取られた値。一般的に言えば、読み出して状態に置くのではなく、必要なときにその都度直接読み取られます。

2. useEffect: 副作用を実行する

副作用とは、現在の実行の結果に影響を与えないコードの一部です。たとえば、関数の外部で変数を変更する場合は、リクエストを開始する必要があります。形式: useEffect(callback, dependencies) 。これは、 componentDidMountcomponentDidUpdatecomponentWillUnmount 3 つのライフサイクル メソッドをカバーします。つまり、useEffect は依存関係を決定し、コンポーネントがレンダリングされるたびにそれを実行します。

useEffect を使用する際の注意点:

依存関係がない場合、各レンダリング後に再実行されます。

使用効果(()=>{
	console.log('re-render') //レンダリングが完了するたびに実行})
  • 空の配列が依存関係として使用された場合、最初の実行時にのみトリガーされ、対応するクラスコンポーネントはcomponentDidMountになります。
使用効果(()=>{
  console.log('did mount') //componentDidMount と同等
},[])
  • コンポーネントが破棄されたときにクリーンアップを実行する関数を返すことができます。
const [size,setResize] = useState({})
使用効果(()=>{
	定数ハンドラ = () => {
    サイズを設定する()
	}
	window.addEventListener('resize',ハンドラ)
	戻り値 () =>{
		window.removeEventListener('resize',ハンドラ)
	}
},[])

要約する

  • useEffect で使用される 4 つのシナリオは、各レンダリング後に実行されます。2 番目の依存関係パラメータは提供されません。たとえば、useEffect(() => {})。
  • 最初のレンダリング後にのみ実行されます。依存関係として空の配列を提供します。たとえば、useEffect(() => {}, [])。
  • 初めて実行され、依存関係が変更された後: 依存関係の配列を提供します。たとえば、useEffect(() => {}, [deps])。
  • コンポーネントがアンマウントされた後に実行され、コールバック関数を返します。たとえば、useEffect() => { return () => {} }, [])。

この記事はこれで終わりです。皆さんのお役に立てれば幸いです。また、123WORDPRESS.COM のその他のコンテンツにも注目していただければ幸いです。

以下もご興味があるかもしれません:
  • React Hook: ステートフックの使い方
  • React Hook: Effect Hookの使い方
  • React の 10 個のフックの紹介
  • React Hooksの詳細な説明
  • Reactのフックについて学ぼう

<<:  DockerHubを自分で構築する方法

>>:  MySQL データ操作 - DML ステートメントの使用

推薦する

MySQLのGROUP BYステートメントを最適化する方法

MySQL で、id、a、b の 3 つのフィールドを持つ新しいテーブルを作成します。次のように、同...

MySQL 8.0.12 のインストールと環境変数の設定チュートリアル (Win10 の場合)

Windows 10 プラットフォームでの MySQL のインストール、構成、起動、ログイン、環境...

計算プロパティとリスナーの詳細

目次1. 計算されたプロパティ1.1 基本的な例1.2 計算プロパティキャッシュとメソッド1.3 計...

MySQL 5.7.17 圧縮パッケージのインストール不要の構成プロセス図

MySQL データベース管理ソフトウェアには、エンタープライズ エディションとコミュニティ エディシ...

vue3 統合 API における vue2 の $refs の代替方法についての簡単な説明

vue2 プロジェクト開発の経験があれば、$refs に精通しているでしょう。 vue3 の急激なア...

Vue 構成リクエストの複数サーバーソリューションの詳細な説明

1. 解決策1.1 インターフェースコンテキストパスの説明2 つのバックエンド インターフェイス サ...

MySQL 5.7.33 インストール プロセスの詳細な図解

目次インストールパッケージのダウンロードインストール環境変数の設定インストールが成功したか確認する記...

Ubuntu での MySQL へのリモート ログインのインストールと設定に関するチュートリアル

この記事では、MySQLのインストールと設定のリモートログインチュートリアルを参考までに紹介します。...

WEB中国語フォントアプリケーションガイド

Web 上でフォントを使用することは、基本的なスキルであると同時に芸術でもあります。英語のフォントに...

Nodejs での WeChat アプレット メッセージ プッシュの実装

サブスクリプションメッセージテンプレートを選択または作成するWeChat アプレットにログインし、「...

Vue3とTypeScriptを組み合わせたプロジェクト開発の実践記録

目次概要1. コンポジションAPI 1. ref と reactive の違いは何ですか? 2. 周...

フォームにファイルをアップロードした後にアクションを保存するよう促す理由と解決策

jsonデータはhtml形式で返される必要がありますつまり、 response.setContent...

CentOS 7 で MySQL 8 の複数のインスタンスを設定する詳細なチュートリアル (必要な数だけ設定できます)

原因最近、プロジェクトのリファクタリングを始めたのですが、マスタースレーブと読み取り書き込み分離を使...

Linux カーネルの copy_{to, from}_user() に関する考察

目次1. copy_{to,from}_user() とは何か1. copy_{to,from}_u...

CSSはボックスコンテナ(div)の高さを常に100%に設定します。

序文ブラウザをどのようにズームしても、ボックス コンテナーの高さを常に 100% に保つ必要がある場...