How to debounce createAsyncThunk from Redux Toolkit
Asked Answered
P

3

6

I am migrating over from Redux to Redux Toolkit. The simplified code I have here is for debounced update using lodash/debounce.

import debounce from "lodash/debounce";

const updateApplication = async (app, dispatch) => {
const state = getState();

try {
  const result = await update(app);
  dispatch({
    type: UPDATE,
    result: result
  });
    } catch (err) {
    console.log(err);
    }
  };

export default debounce(updateThunk, 2000);

The problem is when I move over to createAsyncThunk it does not get executed.


const updateApp = createAction("app/update");
const updateApplication = createAsyncThunk(
  "app/updateDebounced",
  async (app, { dispatch }) => {
   
    try {
      const result = await update(app);
          dispatch(updateApp(result))
        );
      }
    } catch (err) {
      // console.log(err);
    }
  }
);

export default debounce(updateApplication, 2000)

How do I make it work?

Pneumococcus answered 7/7, 2021 at 7:31 Comment(0)
T
7
const updateApp = createAction("app/update");
const handler = async (app, { dispatch }) => {
    try {
      const result = await update(app);

      dispatch(updateApp(result));
    } catch (err) {
      // console.log(err);
    }
}
const debouncedHandler = debounce(handler, 2000);

export default createAsyncThunk(
  "app/updateDebounced",
  debouncedHandler
);
Twosided answered 14/7, 2021 at 3:28 Comment(0)
A
0

A debounced analogue of createAsyncThunk from @reduxjs/toolkit

import { createAsyncThunk } from '@reduxjs/toolkit';

/**
 * A debounced analogue of the `createAsyncThunk` from `@reduxjs/toolkit`
 * @param {string} typePrefix - a string action type value
 * @param payloadCreator - a callback function that should return a promise containing the result
 *   of some asynchronous logic
 * @param {number} wait - the number of milliseconds to delay.
 * @param {Object} [options] - the options object
 * @param {number} [options.maxWait = 0] - The maximum time `payloadCreator` is allowed to be
 * delayed before it's invoked.
 * @param {boolean} [options.leading = false] - Specify invoking on the leading edge of the timeout.
 */
const createDebouncedAsyncThunk = (typePrefix, payloadCreator, wait, options) => {
  const { maxWait = 0, leading = false } = options ?? {};
  let timer = 0;
  let maxTimer = 0;
  let resolve;
  const invoke = () => {
    clearTimeout(maxTimer);
    maxTimer = 0;
    if (resolve) {
      resolve(true);
      resolve = undefined;
    }
  };
  const cancel = () => {
    if (resolve) {
      resolve(false);
      resolve = undefined;
    }
  };
  return createAsyncThunk(typePrefix, payloadCreator, {
    condition() {
      const immediate = leading && !timer;
      clearTimeout(timer);
      timer = setTimeout(() => {
        invoke();
        timer = 0;
      }, wait);
      if (immediate) return true;
      cancel();
      if (maxWait && !maxTimer) maxTimer = setTimeout(invoke, maxWait);
      return new Promise(res => {
        resolve = res;
      });
    },
  });
};

export default createDebouncedAsyncThunk;
Archaeornis answered 3/3, 2022 at 13:58 Comment(0)
B
0

Here is how I am doing it with typescript and lodash to make a debounced call to an api

import { createAsyncThunk, AsyncThunkPayloadCreator } from '@reduxjs/toolkit';
import { debounce } from 'lodash';

// Interface for my api call
interface UpdateParams {
     object_id: number;
     input_field_a: string;
     input_field_b: string;
}

// Handler method for asyncThunk
const updateHandler: AsyncThunkPayloadCreator<any, UpdateParams, {}> = async (params: UpdateParams, { rejectWithValue }) => {
    const { object_id, ...values } = params;
    const response = await window.api.put(`api/object/${object_id}`, values);
    return response && response.data ? response.data : rejectWithValue('Failed to update object');
}

// Create debounced handler with timer of 1 second
const debouncedHandler = debounce(updateHandler, 1000);

// AsyncThunk method
const updateObject = createAsyncThunk(
    'update/object',
    debouncedHandler
);

Burdensome answered 19/2, 2023 at 14:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.