使用lodash debounce返回promise

问题描述 投票:0回答:2

使用 React、react-final-form 和 lodash debounce 函数,我想验证用户名是否尚未使用(该字段正在使用 react-final-form)。

我在让 debounce 函数从获取请求返回已解决的承诺时遇到问题。

我提供了以下 codesandbox 链接来演示我的问题:

请有人告诉我为什么我的代码不起作用。

验证的入口点来自

中 validate 属性中引用的 this.isNameUnique 调用

import React from "react";
import { Field, Form } from "react-final-form";
import { debounce } from "lodash";

class DemoForm extends React.Component {
  getIsNameUnique = name => {
    console.log("getIsNameUnique", name);

    // fake fetch request
    return async name => {
      const asyncResponse = await new Promise(resolve =>
        setTimeout(resolve({ name: true }), 1000)
      );
      console.log("async api response", asyncResponse);
      return asyncResponse;
    };
  };

  debounceCreativeName = name => {
    console.log("debounceCreativeName", name);
    return new Promise(resolve => {
      debounce(() => resolve(this.getIsNameUnique(name)), 2000);
    });
  };

  isNameUnique = async name => {
    const isNameAvailable = await this.debounceCreativeName(name);
    console.log("isNameAvailable", isNameAvailable);
    return isNameAvailable;
  };

  render() {
    return (
      <Form
        onSubmit={() => null}
        render={({ handleSubmit, reset, submitting, pristine, values }) => {
          return (
            <form onSubmit={handleSubmit}>
              <Field name="name" validate={this.isNameUnique}>
                {({ input, meta }) => {
                  return (
                    <input
                      style={{
                        display: "flex",
                        height: "40px",
                        fontSize: "24px"
                      }}
                      autoComplete="off"
                      {...input}
                      type="text"
                      placeholder="Enter the name"
                    />
                  );
                }}
              </Field>
            </form>
          );
        }}
      />
    );
  }
}

export default DemoForm;

javascript reactjs lodash react-final-form
2个回答
9
投票

这个沙箱解决了您的问题。

您不应该在每个渲染上创建新的去抖函数:

return new Promise(resolve => {
  debounce(() => resolve(this.getIsNameUnique(name)), 2000);
});

相反,你应该用去抖动包装整个函数

isNameUnique
(请参阅我的沙箱)。通过在每次点击时创建一个新的去抖函数,它无法“记住”哪个函数被调用或者哪个函数将被再次调用。 这将防止去抖。

此外,通过异步

getIsNameUnique
,您可以仅使用await 来降低其复杂性。


0
投票

到目前为止我知道lodasahe的debounce不允许你返回promise,但你可以手动处理它!

我们在这里可以做的只是将去抖函数包装到另一个函数中,该函数将具有与原始去抖函数相同的参数接口。这个包装器将返回 Promise,并在 lodashe 的 debounce 被触发时管理我们的 Promise 解析执行。

这是具有泛型类型的打字稿示例。

export type FnWithAnyArgs<T = any> = (...args: any[]) => T | Promise<T>;

export function debouncePromisify<T = void>(
  fn: FnWithAnyArgs<T>,
  timeout: number
): (...args: Parameters<typeof fn>) => Promise<T> {
  let resolver: ((value: T | Promise<T>) => void) | null = null;

  const fnDebounced = _debounce((...args: Parameters<typeof fn>) => {
    const res = fn(...args);
    resolver?.(res);
    resolver = null;
  }, timeout);

  return (...args: Parameters<typeof fn>) => {
    return new Promise((resolve) => {
      resolver = resolve;
      fnDebounced(...args);
    });
  };
}

---- 使用示例

async function isNameUnique() {
  let isUnique = true;
  ...your logic with the backend validation etc.
  return isUnique;
}

...
const isNameUniqueDebounced = debouncePromisify<boolean>(
  this.isNameUnique,
  300
);

... 
async function setName() {
   ... do things here like setting value or the loading status
  // VS code will know that isAvailable is boolean automatically
  const isAvailable = await this.isNameUniqueDebounced();
  ...do things only after the debounce will be executed
}
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.