如何从 Redux Toolkit 去抖动 createAsyncThunk
How to debounce createAsyncThunk from Redux Toolkit
我正在从 Redux 迁移到 Redux Toolkit。我这里的简化代码是使用 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);
问题是当我转到 createAsyncThunk 时它没有被执行。
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)
如何让它发挥作用?
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
);
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;
我正在从 Redux 迁移到 Redux Toolkit。我这里的简化代码是使用 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);
问题是当我转到 createAsyncThunk 时它没有被执行。
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)
如何让它发挥作用?
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
);
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;