フックを使用して React コンポーネントを書くときに注意すべき 5 つの点

フックを使用して React コンポーネントを書くときに注意すべき 5 つの点

Hook は React16.8 で追加された新しい機能です。 React の公式ドキュメントでは React フックの関連概念について説明されていますが、公式ドキュメントを読むだけではフックをうまく使いこなすのは難しく、フックを書く際に罠やエラーに陥りやすいです。この記事では5つの悪い場所をまとめています。

01. レンダリングが不要な場合はuseStateを使用する

関数コンポーネントでは、 useStateを使用して状態を管理できます。これにより、状態管理が非常に簡単になりますが、悪用される可能性も高くなります。次のコードサンプルを通じて、見落とされやすい領域を確認してみましょう。

非推奨×

関数 ClickButton(props){
 定数[count, setCount] = setState(0)
 定数onClickCount = () => {
  setCount((c) => c + 1)
 }
 定数onClickRequest = () => {
  apiCall(カウント)
 }
 
 戻る (
  <div>
   <button onClick={onClickCount}>クリック</button>
   <button onClick={onClickRequest}>送信</button>
  </div>
 )
}

問題: 上記のコードをよく見ると、一見何も問題はありません。ボタンをクリックすると、 countが更新されます。しかし、問題はここにあります。 return 部分はcount状態を使用しておらず、 setCountごとにコンポーネントが 1 回再レンダリングされますが、これは必要なことではありません。 余分なレンダリングによってページのパフォーマンスが悪化するため、次のようにコードを変更します。

推奨√
コンポーネント宣言サイクル中に保存できる変数だけが必要で、変数の更新でコンポーネントを再レンダリングする必要がない場合は、 useRefフックを使用できます。

関数 ClickButton(props){
 定数カウント = useRef(0)
 定数onClickCount = () => {
  count.current++
 }
 定数onClickRequest = () => {
  apiCall(カウント.現在)
 }

 戻る (
  <div>
   <button onClick={onClickCount}>クリック</button>
   <button onClick={onClickRequest}>送信</button>
  </div>
 )
}

02. リンクの代わりにrouter.pushを使用する

React SPA アプリケーションでは、 react-routerを使用してルート ジャンプを処理します。多くの場合、次のコードに示すように、コンポーネントにボタンを記述し、ボタン イベントをクリックしてルート ジャンプを処理します。

非推奨×

関数 ClickButton(props){
 定数履歴 = useHistory()
 定数onClickGo = () => {
  history.push('/where-page')
 }
 戻る <button onClick={onClickGo}>どこへ移動する</button>
}

問題: 上記のコードは機能しますが、アクセシビリティの要件を満たしていません。ボタンはスクリーン リーダーによってリンクとして認識されません。したがって、コードを次のように変換できます。

推奨√

関数 ClickButton(props){
 戻る <Link to="/next-page">
  <span>どこへ行く</span>
 </リンク>
}

03. useEffectでアクションを処理する

場合によっては、React が DOM を更新した後に、追加のコードを実行したいことがあります。たとえば、ネットワーク リクエストの送信、DOM の手動変更、ログの記録などです。

非推奨×

関数 DataList({ onSuccess }) {
 const [ロード中、setLoading] = useState(false);
 定数[エラー、setError] = useState(null);
 const [データ、setData] = useState(null);

 定数フェッチデータ = () => {
  読み込みをtrueに設定します。
  呼び出しAPI()
   .then((res) => setData(res))
   .catch((err) => setError(err))
   .finally(() => setLoading(false));
 };

 使用効果(() => {
  フェッチデータ();
 }, []);

 使用効果(() => {
  if (!ロード中 && !エラー && データ) {
   成功の場合();
  }
 }, [読み込み中、エラー、データ、onSuccess]);

 <div>データ: {data}</div> を返します。
}

問題: 上記のコードでは 2 つのuseEffectが使用されています。最初の useEffects は非同期データを要求するために使用され、2 番目の useEffects はコールバック関数を呼び出すために使用されます。 2 番目のuseEffectの実行は、最初の非同期リクエスト データが成功した場合にのみトリガーされます。ただし、2 番目のuseEffectの依存関係が最初のuseEffectの成功したリクエスト データによって完全に制御されることを完全に保証することはできません。したがって、コードを次のように変換できます。

推奨√

関数 DataList({ onSuccess }) {
 const [ロード中、setLoading] = useState(false);
 定数[エラー、setError] = useState(null);
 const [データ、setData] = useState(null);

 定数フェッチデータ = () => {
  読み込みをtrueに設定します。
  呼び出しAPI()
   .then((res) => {
    データ設定(res)
    成功時()
    })
   .catch((err) => setError(err))
   .finally(() => setLoading(false));
 };

 使用効果(() => {
  フェッチデータ();
 }, []);
 <div>データ: {data}</div> を返します。
}

04. 単一責任コンポーネント

コンポーネントを複数の小さなコンポーネントに分割する必要があるのはいつですか?コンポーネントツリーを構築するにはどうすればいいですか?これらすべての問題は、コンポーネントベースのフレームワークを使用するときに毎日発生します。ただし、コンポーネントを設計するときによくある間違いは、2 つのユースケースを 1 つのコンポーネントに結合することです。

非推奨×

関数 Header({ menuItems }) {
 戻る (
  <ヘッダー>
   <ヘッダー内部メニュー項目={メニュー項目} />
  </ヘッダー>
 );
}

関数 HeaderInner({ menuItems }) {
 isMobile() を返します? <BurgerButton menuItems={menuItems} /> : <Tabs tabData={menuItems} />;
}

問題: このアプローチでは、 HeaderInnerコンポーネントは同時に 2 つの異なる機能を実行しようとします。一度に複数の機能を実行するのは理想的ではありません。さらに、コンポーネントを他の場所でテストしたり再利用したりすることが難しくなります。したがって、コードを次のように変換できます。

推奨√

条件を 1 レベル上に移動すると、コンポーネントの目的がわかりやすくなり、同時に 2 つの異なることを行おうとするのではなく、コンポーネントが<Tabs/>または<BurgerButton/>のいずれか 1 つの責任のみを持つようになります。

関数 Header(props) {
 戻る (
  <ヘッダー>
   {isMobile() ? <BurgerButton menuItems={menuItems} /> : <Tabs tabData={menuItems} />}}
  </ヘッダー>
 )
}

05. 単一責任の使用効果

componentWillReceivePropscomponentDidUpdateメソッドを比較することで、 userEffectの素晴らしさに気づきました。ただし、useEffect が適切に使用されていない場合は、問題が発生する可能性があります。

非推奨×

関数の例(props) {
 定数 location = useLocation();
 定数フェッチデータ = () => {
  /* API を呼び出す */
 };

 const updateBreadcrumbs = () => {
  /* パンくずリストを更新しています */
 };

 使用効果(() => {
  フェッチデータ();
  パンくずリストを更新します。
 }, [location.pathname]);

 戻る (
  <div>
   <パンくず />
  </div>
 );
}

問題: 上記のuseEffect同時に 2 つの副作用をトリガーしますが、それらすべてが必要な副作用ではないため、次のようにコードを変更できます。

推奨√

1 つの useEffect から 2 つの副作用を分離します。

関数の例(props) {
 定数 location = useLocation();

 定数フェッチデータ = () => {
  /* API を呼び出す */
 };

 const updateBreadcrumbs = () => {
  /* パンくずリストを更新しています */
 };

 使用効果(() => {
  フェッチデータ();
  パンくずリストを更新します。
 }, [location.pathname]);

 戻る (
  <div>
   <パンくず />
  </div>
 );
}

参照:

2020 年に React コンポーネント (フック付き) を書くときによくある 5 つの間違い

以上が、Reactコンポーネントを記述する際にフックを使用する際に注意すべき5つのポイントの詳細です。Reactコンポーネントを記述する際のフックの詳細については、123WORDPRESS.COMの他の関連記事にも注目してください!

以下もご興味があるかもしれません:
  • Reactフックの長所と短所
  • React Hooks の一般的な使用シナリオ (概要)
  • Reactフック入門チュートリアル
  • Reactフックとzarmコンポーネントライブラリ構成に基づいてh5フォームページを開発するためのサンプルコード
  • Reactはフックを使用して、制御されたコンポーネントの状態バインディングを簡素化します。
  • 今年最もエキサイティングな React の新機能、React Hooks を 30 分でマスターする
  • 完全なReact Hooksの練習を記録する
  • React Hooksの深い理解と使用
  • Reactフックの仕組み

<<:  Nginx 静的サービス設定の詳細な説明 (ルートとエイリアスの指示)

>>:  Linux での MySQL 5.6.27 インストール チュートリアル

推薦する

動的および静的分離を実現する nginx のサンプルコード

1. nginxの動的と静的の分離の簡単な設定web1は静的サーバー、web2は動的サーバー、nod...

ドラッグ効果を実現するための純粋なCSSコード

目次1. ドラッグ効果の例2. CSS実装の原則3. CSS実装の詳細4. CSSレイアウト1. 固...

IE環境では、divの高さはフォントの高さよりも大きくなければならないと規定されています。

コードをコピーコードは次のとおりです。 <div class="content&qu...

Docker+daocloudはフロントエンドプロジェクトの自動構築とデプロイを実現します

自動プロジェクト展開は大企業やユニコーン企業でよく使用され、手動でプロジェクトを展開するよりも効率的...

MySQL における一般的なランキングの問題をいくつかまとめます

序文:一部のアプリケーション シナリオでは、成績や年齢によるランキングなど、ランキングの問題が発生す...

MySQL マスター スレーブ データベースが同期されない問題を解決する 2 つの方法

目次MySQL マスター スレーブ データベースが同期されない問題を解決する 2 つの方法1. 非同...

MySQLはこのような更新文を決して書きません

目次序文原因現象なぜ?分析要約する序文今日は、非常に典型的な MySQL の「落とし穴」についてお話...

MySQL のロックに関する問題

ロックの分類:データ操作の粒度から:テーブルロック:操作時にテーブル全体がロックされます。行ロック:...

Typescriptを使用してWeChatミニプログラムを開発するための詳細な手順

Typescript の利点については詳しく説明する必要はありません。ご興味があれば、(https:...

nginx proxy_cache バッチキャッシュクリアスクリプトの紹介

前書き: 以前、公式の nginx proxy_cache を CDN 静的キャッシュとして使用して...

Vue データの応答性の概要

データの応答性について話す前に、Vue はデータに対して具体的に何を行うのかという非常に重要な問題を...

MySQL ソート機能の詳細

目次1. 問題のシナリオ2. 原因分析3. 解決策4. 知識を広げる4.1 クエリの最適化を制限する...

mysql8.0 パスワードを忘れた場合の修正とネットコマンドのサービス名が無効になる問題

cmdにnet start mysqlと入力すると、プロンプトが表示されます: サービス名が無効です...

MySQLの一般的なメモリ不足による起動失敗に対する完璧な解決策

1. MySQLが正常に起動しない場合は、エラーログ/var/log/mysql/error.log...

CSS3は背景画像にマスクを設定し、マスクスタイルの継承の問題を解決します。

多くの場合、透明度の設定やぼかしなど、写真の背景を加工する必要があります。 ただし、背景画像が配置さ...