自動補完する🤯 共通ミスとその解決法


反応と約束ベースのHTTPクライアントでAutocompleteを作りましょう.ちょっと少し些細なそれから、それは思われます.
以下の例では、共通の間違いが表示されます.また、バトルテストパターンを使用してautocomplete反応コンポーネントを作成する方法を示します.

問題


最初の自動反応を書くときに最も些細な間違いは、各入力変更イベントの要求をすることであり、彼らが到着すると応答を使用します.
コードは次のようになります.
import React, { Fragment, useState } from "react";
import { api } from "./api";

export const AutocompleteTrivialMistake: React.FC = () => {
  const [apiResult, setApiResult] = useState('');
  const handleChange = e => {
    api(e.target.value)
      .then((result)=>{
        setApiResult(result);
      });
  };

  return (
    <div>
      <h3>AutocompleteTrivialMistake</h3>
      <input onChange={handleChange} />
      <p>
        Search result: {apiResult}
      </p>
    </div>
    );
};

Note - at the bottom of the page there's a stackblitz with all of the examples shown here.


そして、開発中に使用するときは以下のようになります.

クライアントがそれを使用するときに起こるバグは次のようになります.

言葉にする
  • 期待される-すべての文字を高速に削除するときには、最新のリクエスト(空の文字列)からの最新の応答が必要です.
  • 実際は、すべての文字を高速に削除する場合、古いリクエスト(空でない文字列)からの最新の応答が表示されます.
  • このバグは、しばしば開発中にうまく動作するため、トリッキーですが、それは生産上のバグが発生します.
    これは古いリクエストが新しいリクエストが送られてキャンセルされないために起こります.これは、新しい要求の後、古い要求が戻るこのバグに私たちをもたらします.我々が得る最新のレスポンスが我々がタイプした最新の検索ストリングを代表していないという意味.生じる🤯

    🤯


    このバグをどこかで見たら、このバグを再現する簡単な方法は文字を削除することです.文字の数を減らすと、検索が軽くなり、より高速なレスポンスが得られます.
    ではどうやって解決できるのか?

    些細な解決ではなく、まだ防弾


    我々がしなければならない最初で最も明白なことは、より新しい要求がなされるとき、古い要求を取り消すことです.
    import React, { Fragment, useState } from "react";
    import { api } from "./api";
    
    let promise;
    
    export const AutocompleteTrivialSolution: React.FC = () => {
      const [apiResult, setApiResult] = useState("");
      const handleChange = e => {
        promise = api(e.target.value);
        const localPromise = promise;
        promise.then(result => {
          // Only send use the response of the latest request
          if(promise === localPromise){
            setApiResult(result);
          }
        });
      };
    
      return (
        <div>
          <h3>AutocompleteTrivialSolution</h3>
          <input onChange={handleChange} />
          <p>API search result for: {apiResult}</p>
        </div>
      );
    };
    
    これは実際に動作しますが、コンポーネントが単一の場所で使用される限り.複数の場所にコンポーネントを持つと、コンポーネントのすべてのインスタンスが同じローカル変数を使用します.それは悪い習慣です、そして、thoさえバグを作成しそうでありません、それはまだ予想外の行動のための開始を持ちます.

    完全なアプローチ


    この段階では、各コンポーネントインスタンスのローカルキャンセルメカニズムを作成する必要があることは明らかです.我々はそれを使用している各コンポーネントのインスタンスに対して作成された新しいインスタンスを持つクラスを作成することによってそれを達成することができます.各インスタンスは、そのコンポーネントによって行われたリクエストのみをキャンセルします.飛び込みましょう.
    import React, { Fragment, useState, useEffect } from "react";
    import { api } from "./api";
    
    export class Api {
      promise;
      async request(text) {
        this.promise = api(text);
        const localPromise = this.promise;
        const result = await this.promise;
    
        if (this.promise === localPromise) {
          return result;
        }
      }
    }
    
    export const AutocompleteCompleteSolution: React.FC = () => {
      const [apiResult, setApiResult] = useState("");
      const [apiClient, setApiClient] = useState();
    
      useEffect(() => {
        const client = new Api();
        setApiClient(client);
      }, []);
    
      const handleChange = async (e) => {
        if (!apiClient) {
          return;
        }
        const result = await apiClient.request(e.target.value);
        setApiResult(result);
      };
    
      return (
        <div>
          <h3>AutocompleteCompleteSolution</h3>
          <input onChange={handleChange} />
          <p>API search result for: {apiResult}</p>
        </div>
      );
    };
    
    

    読書ありがとう!


    この動画はお気に入りから削除されています.
    あなた
    アダム.