繁体   English   中英

如何去抖动 Formik Field ReactJS

[英]How to debounce Formik Field ReactJS

我想对 Formik <Field/>进行去抖动,但是当我在该字段中输入时,去抖动似乎不起作用。 我也试过 lodash.debounce、throttle-debounce 和同样的结果。 如何解决这个问题?

CodeSandbox - https://codesandbox.io/s/priceless-nobel-7p6nt

片段

import ReactDOM from "react-dom";
import { withFormik, Field, Form } from "formik";

const App = ({ setFieldValue }) => {
  let timeout;
  const [text, setText] = useState("");

  const onChange = text => {
    if (timeout) clearTimeout(timeout);
    timeout = setTimeout(() => setText(text), 750);
  };

  return (
    <Form>
      <Field
        type="text"
        name="textField"
        placeholder="Type something..."
        onChange={e => {
          onChange(e.target.value);
          setFieldValue("textField", e.target.value);
        }}
        style={{ width: "100%" }}
      />
      <br />
      <br />
      <div>output: {text}</div>
    </Form>
  );
};

const Enhanced = withFormik({
  mapPropsToValues: () => ({
    textField: ""
  }),
  handleSubmit: (values, { setSubmitting }) => {
    setSubmitting(false);
    return false;
  }
})(App);

ReactDOM.render(<Enhanced />, document.getElementById("root"));
  const [text, setText] = useState("");
  const [t, setT] = useState(null);

  const onChange = text => {
    if (t) clearTimeout(t);
    setT(setTimeout(() => setText(text), 750));
  };

我想建议将调用移到超时功能内。

const App = ({ setFieldValue }) => {
      let timeout;
      const [text, setText] = useState("");

      const onChange = text => {
        if (timeout) clearTimeout(timeout);
        timeout = setTimeout(() => {
          setText(text);
          //changing value in container
          setFieldValue("textField", text);
        }, 750);
      };

      return (
        <Form>
          <Field
            type="text"
            name="textField"
            placeholder="Type something..."
            onChange={e => {
              onChange(e.target.value);
            }}
            style={{ width: "100%" }}
          />
          <br />
          <br />
          <div>output: {text}</div>
        </Form>
      );
    };

使用自定义钩子

这是从@Skyrocker 提供的答案中抽象出来的

如果您发现自己经常使用此模式,则可以将其抽象为自定义 hook

hooks/useDebouncedInput.js

const useDebouncedInput = ({ defaultText = '', debounceTime = 750 }) => {
  const [text, setText] = useState(defaultText)
  const [t, setT] = useState(null)

  const onChange = (text) => {
    if (t) clearTimeout(t)
    setT(setTimeout(() => setText(text), debounceTime))
  }

  return [text, onChange]
}

export default useDebouncedInput

components/my-component.js

const MyComponent = () => {
  const [text, setTextDebounced] = useDebouncedInput({ debounceTime: 200 })

  return (
    <Form>
      <Field
        type="text"
        name="textField"
        placeholder="Type something..."
        onChange={(e) => setTextDebounced(e.target.value)}
      />
      <div>output: {text}</div>
    </Form>
  )
}

使用 Redux、获取和验证的示例

下面是对去抖动字段验证器使用自定义钩子的部分示例。

注意:我确实注意到 Field 验证似乎没有验证onChange但是当你在你的去抖动更新执行后离开现场时你可以期待它onBlur (我没有尝试与它竞争或长时间去抖动看看会发生什么)。 这可能是一个应该打开的错误(我正在开票)。

hooks/use-debounced-validate-access-code.js

const useDebouncedValidateAccessCode = () => {
  const [accessCodeLookUpValidation, setAccessCodeLookUpValidation] = useState()
  const [debounceAccessCodeLookup, setDebounceAccessCodeLookup] = useState()
  const dispatch = useDispatch()

  const debouncedValidateAccessCode = (accessCodeKey, debounceTime = 500) => {
    if (debounceAccessCodeLookup) clearTimeout(debounceAccessCodeLookup)

    setDebounceAccessCodeLookup(
      setTimeout(
        () =>
          setAccessCodeLookUpValidation(
            dispatch(getAccessCode(accessCodeKey)) // fetch
              .then(() => undefined)               // async validation requires undefined for no errors
              .catch(() => 'Invalid Access Code'), // async validation expects a string for an error
          ),
        debounceTime,
      ),
    )

    return accessCodeLookUpValidation || Promise.resolve(undefined)
  }

  return debouncedValidateAccessCode
}

some-component.js

const SomeComponent = () => {
  const debouncedValidateAccessCode = useDebouncedValidateAccessCode()

  return (
    <Field
      type="text"
      name="accessCode"
      validate={debouncedValidateAccessCode}
    />
  )
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM