Debonseをsubmitイベントハンドラに適用してサーバとの通信を最小限に抑える


ケース


現在実施されている状況は以下の通りである.
Inputにフォーカスした場合にenterを押すか、submitボタンを押してonsubmitイベントを起動し、サーバに保存することを実現しました.また、データベースに正常に保存されると、snackbar形式で通知が送信されます.
このとき、ユーザーが「enter」または「submit」ボタンを開くのを防止するために、最新イベントを1回のみ処理するように変更します.
これにより、サーバとの通信を最小限に抑えるとともに、snackbar通知を一度表示することもできる.

debonseが適切かどうか


現在redux-sagaが使用されているため、このsagaでtakeLatestを使用する方法もある.しかし、sagaに行く必要はなく、クライアント側で直接処理するのが最も直接的で、最も迅速です.
だから方法を探しているうちにthrottle,debonseというキーワードを見つけました.
まずスロットルバルブとdebonseが混ざっていて、説明をまとめるとこうなります.

throttle


一定時間(ex.500 ms)に発生した複数のイベントの中から最新のイベントを発動します.
つまり、500 msごとにアクティビティが開始されます.
たとえば、自動補完機能から自動完了のキーワードをインポートする必要がある場合、apiを一定期間インポートする必要がある場合に使用します.

debounce


一定時間(ex.500 ms)内にイベントが発生しない場合は、最後のイベントを発動します.
つまり、しばらく待っている間に、イベントが発生した場合、再びしばらく待っているということです.

両者の中で適当なのはdebonseです


私の場合、submitアクティビティを1回だけ開始したいので、debonseを適用するのが適切です.
ユーザーがsubmitアクティビティを複数回開始しても、一度起動してvalueをサーバに渡すだけです.

アプリケーション1


適用する前に、Web API setTimeout()の戻り値を知る必要がある.

リターン量は、setTimeout()からなるタイマーのID値である.
その後、このタイマをキャンセルするには、clearTimeout()関数のパラメータを使用してタイマのID値を渡すことができます.
handleSubmit関数にタイマーを加えて実装します.
const [submitTimer, setSubmitTimer] = useState<NodeJS.Timeout>();

const handleSubmit = useCallback((event : React.FormEvent |  React.FocusEvent)=>{
    event.preventDefault();
  
  	/* 예외처리 코드들 */
  
    submitTimer && clearTimeout(submitTimer);

    const newTimer = setTimeout(()=>{
      saveTask(id,inputValue);
    },500);
    setSubmitTimer(newTimer);

  },[saveTask,deleteTask,id,inputValue,title,submitTimer])
私のコードでは、saveTask()関数はサーバと直接通信する関数です.
したがって、submitでは、saveTask()関数が呼び出されるのは、関数の上部で異常処理が行われ、本当にsaveが必要である場合に限られる.
  • 状態でタイマIDを管理する.
  • submitになると、タイマーを初期化し、800 ms待ってsaveTask()を起動します.
  • 800 ms待ちの場合、またコミットした場合は2回繰り返します.
  • 最終的に、サーバと通信するsaveTask()は、800 ms後に実行されるのを完全に待つ必要がある.
    +)アプリケーションの結果をgifで表示するのは難しいので,アプリケーション2を連写する.

    アプリケーション2



    他の場所でも役に立ちます.
    以上のgifはaddボタンが複数回連続している場合、調音効果が良好な結果となります👍
    次のコードは、サブ要素を追加するときにaddボタンをクリックするコードに適用されます.
    const [addTimer, setAddTimer] = useState<NodeJS.Timeout>();
    
      const handleAdd = (()=>{
        if(!onAdd) return;
        addTimer && clearTimeout(addTimer);
    
        const newTimer = setTimeout(onAdd,400);
        setAddTimer(newTimer);
      })
    
    ここでonAddコールバック関数はoptional propとして入るので,ない場合は例外的に扱う.

    時間の指定


    500 msは私が任意に設定した値で、短すぎるとDebonseの役割が減り、長すぎるとユーザーの立場に立ってコミュニケーションがうまくいかないと感じます.800 ms,1000 msなどの実験結果は,500 msが適切であることを示した.
    以上の2番目の適用箇所はランダムな連撃を防ぐため400 msに適用されます.

    残念な点


    上のaddボタンはうまく適用されていましたが、すぐに途切れなくて残念でした.
    なぜなら、追加するとサーバに追加された論理で実現されるからです.
    サーバにデータを追加せずにディレクトリ更新データを追加して表示した場合、サーバにデータは保存されませんので、デバッガを適用する必要はありません.submitに注意すればいいだけです.

    Ref

  • https://pks2974.medium.com/throttle-%EC%99%80-debounce-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0-2335a9c426ff
  • https://developer.mozilla.org/en-US/docs/Web/API/setTimeout
  • https://velog.io/@tjdud0123/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%94%94%EB%B0%94%EC%9A%B4%EC%8B%B1-%EA%B0%84%EB%8B%A8-%EA%B5%AC%ED%98%84-react-debounce