入力を取り込んでいる非同期データのために反応フックでlodash負債を使用するか、カスタムフックを使用してください.


TLR反応関数コンポーネント内でLodDashデフラグを統合するコード例


https://codesandbox.io/s/react-debounced-data-fetching-input-630jk?file=/pages/index.js
UseDeadounceカスタムフックを使用したコード例をリンクします.
https://codesandbox.io/s/react-debounced-data-fetching-input-630jk?file=/pages/with-use-debounce-custom-hook.js

自動補完入力で-それは簡単であることになっていた。


私は最近、大きなゲーム会社で開発者の仕事に応募しました.彼らは私に反応してautocompleteコンポーネントを構築するためのオンラインコーディングチャレンジを渡す必要がありました.
その要求は以下のようなものでした.
  • ユーザーの入力と一致するようにデータをサーバ上で取得します.
  • ユーザーがLodDashを使用してタイピングを停止した後、取得した関数を500 ms遅延させます.
  • ユーザー入力と一致するときに暗示リストコンポーネントをレンダリングします.
  • 確かに、Autocompleteは最も簡単な仕事ではありません、しかし、私は最も難しい部分がロダッシュの討論を使っていると決して思いませんでした.

    まあ、予想以上に複雑だった。


    それは1時間の後、私はまだ私の反応コンポーネント内で動作するようにlodashの債務の一部を得ることができなかったことがわかります.悲しいことに、私の最大許容時間は期限切れになり、私の挑戦は失敗しました.

    パーフェクトチャンスは、反応の精神的モデルで改善する。


    失敗の感覚のために悪い感じではなく、私は“反応のフックを使用してLoDashの負債を使用する方法”について読んで、その動機を取ったし、私が学んだことを共有するcodesandboxを作った.

    USEMemoを使用して、変更された変更ハンドラを返す


    lodashを使うことはできません.それを働かせてください.これは、関数の定義をRerenderの間で完全に保つためにusememoまたはusecallbackを必要とします.
    一度それを知って、それは簡単です.
    import { useEffect, useMemo, useState } from "react";
    import debounce from "lodash/debounce";
    
    // References:
    // https://dmitripavlutin.com/react-throttle-debounce/
    // https://stackoverflow.com/questions/36294134/lodash-debounce-with-react-input
    // https://stackoverflow.com/questions/48046061/using-lodash-debounce-in-react-to-prevent-requesting-data-as-long-as-the-user-is
    // https://kyleshevlin.com/debounce-and-throttle-callbacks-with-react-hooks
    
    // Sandbox Link:
    // https://codesandbox.io/s/react-debounced-data-fetching-input-630jk?file=/pages/index.js
    
    const API_ENDPOINT = "https://jsonplaceholder.typicode.com/todos/1";
    const DEBOUNCE_DELAY = 1500;
    
    export default function Home() {
      const [queryResults, setQueryResults] = useState(null);
      const [isDebounced, setIsDebounced] = useState(false);
      const [isLoading, setIsLoading] = useState(false);
      const [error, setError] = useState(null);
    
      const debouncedChangeHandler = useMemo(
        () => debounce((userInput) => fetchQuery(userInput), DEBOUNCE_DELAY),
        []
      );
    
      // Stop the invocation of the debounced function after unmounting
      useEffect(() => {
        return () => {
          debouncedChangeHandler.cancel();
        };
      }, [debouncedChangeHandler]);
    
      function handleUserInputChange(event) {
        const userInput = event.target.value;
        debouncedChangeHandler(userInput);
        setIsDebounced(true);
      }
    
      function fetchQuery() {
        setIsDebounced(false);
        setIsLoading(true);
    
        fetch(API_ENDPOINT)
          .then((res) => res.json())
          .then((json) => {
            setQueryResults(json);
            setIsLoading(false);
          })
          .catch((err) => {
            setError(err);
            setIsLoading(false);
          });
      }
    
      const DisplayResponse = () => {
        if (isDebounced) {
          return <p>fetchQuery() is debounced for {DEBOUNCE_DELAY}ms</p>;
        } else if (isLoading) {
          return <p>Loading...</p>;
        } else if (error) {
          return <pre style={{ color: "red" }}>{error.toString()}</pre>;
        } else if (queryResults) {
          return (
            <pre>
              Server response:
              <br />
              {JSON.stringify(queryResults)}
            </pre>
          );
        }
        return null;
      };
    
      return (
        <main>
          <h1>
            With <em>Lodash</em> Debounce
          </h1>
          <a href="/with-use-debounce-custom-hook">
            Try with useDebounce custom hook instead
          </a>
          <div className="input-container">
            <label htmlFor="userInput">Type here:</label>
            <input
              type="text"
              id="userInput"
              autoComplete="off"
              placeholder={"input is delayed by " + DEBOUNCE_DELAY}
              onChange={handleUserInputChange}
            />
          </div>
          <DisplayResponse />
        </main>
      );
    }
    
    LogDashのデフラグを反応関数コンポーネントで使用するための完全なコード例については、次のJSスターターテンプレートで構築したCodesandbox dev環境を試してください.
    https://codesandbox.io/s/react-debounced-data-fetching-input-630jk?file=/pages/index.js

    2 .カスタムを使用してフックをフェッチします


    import { useEffect, useState } from "react";
    
    // References:
    // https://dev.to/jackzhoumine/comment/1h9c8
    
    // CodesandBox link:
    // https://codesandbox.io/s/react-debounced-data-fetching-input-630jk?file=/pages/with-use-debounce-custom-hook.js
    
    const API_ENDPOINT = "https://jsonplaceholder.typicode.com/todos/1";
    const DEBOUNCE_DELAY = 1500;
    
    export default function DebouncedInput() {
      const [queryResults, setQueryResults] = useState(null);
      const [isDebounced, setIsDebounced] = useState(false);
      const [isLoading, setIsLoading] = useState(false);
      const [error, setError] = useState(null);
    
      const [didMount, setDidMount] = useState(false);
      const [userInput, setUserInput] = useState(null);
      const debouncedUserInput = useDebounce(userInput, DEBOUNCE_DELAY);
    
      useEffect(() => {
        if (!didMount) {
          // required to not call API on initial render
          //https://stackoverflow.com/questions/53179075/with-useeffect-how-can-i-skip-applying-an-effect-upon-the-initial-render
          setDidMount(true);
          return;
        }
        fetchQuery(debouncedUserInput);
      }, [debouncedUserInput]);
    
      function handleUserInputChange(event) {
        setUserInput(event.target.value);
        setIsDebounced(true);
      }
    
      function fetchQuery(debouncedUserInput) {
        setIsLoading(true);
        setIsDebounced(false);
    
        console.log("debouncedUserInput: " + debouncedUserInput);
    
        fetch(API_ENDPOINT)
          .then((res) => res.json())
          .then((json) => {
            setQueryResults(json);
            setIsLoading(false);
          })
          .catch((err) => {
            setError(err);
            setIsLoading(false);
          });
      }
    
      const DisplayResponse = () => {
        if (isDebounced) {
          return <p>fetchQuery() is debounced for {DEBOUNCE_DELAY}ms</p>;
        } else if (isLoading) {
          return <p>Loading...</p>;
        } else if (error) {
          return <pre style={{ color: "red" }}>{error.toString()}</pre>;
        } else if (queryResults) {
          return (
            <pre>
              Server response:
              <br />
              {JSON.stringify(queryResults)}
            </pre>
          );
        }
        return null;
      };
    
      return (
        <main>
          <h1>
            With <em>useDebounce</em> custom hook
          </h1>
          <a href="/">Try with Lodash Debounce instead</a>
          <div className="input-container">
            <label htmlFor="userInput">Type here:</label>
            <input
              type="text"
              id="userInput"
              autoComplete="off"
              placeholder={"input is delayed by " + DEBOUNCE_DELAY}
              onChange={handleUserInputChange}
            />
          </div>
          <DisplayResponse />
        </main>
      );
    }
    
    function useDebounce(value, wait = 500) {
      const [debounceValue, setDebounceValue] = useState(value);
    
      useEffect(() => {
        const timer = setTimeout(() => {
          setDebounceValue(value);
        }, wait);
        return () => clearTimeout(timer); // cleanup when unmounted
      }, [value, wait]);
    
      return debounceValue;
    }
    
    
    UseDebugOfカスタムResponseフックを使用した完全なコード例については、次のJSスターターテンプレートにこのURLで構築したCodesandboxのdev環境を試してみてください.
    https://codesandbox.io/s/react-debounced-data-fetching-input-630jk?file=/pages/with-use-debounce-custom-hook.js

    クレジット


    クレジットはすべて私がファイルのコメントで参照している他のスマートな人々に移動します.これらは、あなたに挑戦についてより良い視点を与えることができるより完全な記事です.
    それは、私はすべての後に眠っているように感じる.しかし、いつものように、実際の課題を学ぶことは最適です.良い仕事を続けなさい.チアーズ.
    アレックス