Formik即时反馈输入框

Formik instant feedback input box

我正在尝试使用 Formik 制作一个具有即时反馈的输入框组件。我希望输入框在用户输入匹配预定义字符串(“答案”)时变为绿色,如果输入匹配答案的前缀(包括空字符串)则变为灰色,否则变为红色。此字符串存储为初始值 values.answer 的 属性。 Formik validate 函数检查输入是否等于 values.answer 并设置 values.correct = true。然后,我创建了一个对应于绿色输入框的 css class,并根据 values.correct 的值设置输入的 class 名称。问题是当我点击输入框的焦点(即 onBlur)时,它似乎只会更新(即通过正确的输入变为绿色)。我希望它能在 Change 上工作。我该怎么做?

这里是相关的代码沙箱:https://codesandbox.io/s/instant-feedback-box-lub0g?file=/src/Frame.js

很酷的问题,但是您的代码有点过于复杂了一些反馈:

    默认情况下,
  • touched 在 onBlur 期间设置为 true。您可以使用 setTouched() 覆盖它,但我发现在表单
  • 中使用 values 而不是 touched 更简单
  • 尽量保持 values 尽可能小,它仅用于访问输入值,因此不需要将 hintanswer 分配给它
  • 验证函数的目的是 return 一个 errors 对象而不是设置值,所以删除像 values.correct = true
  • 这样的赋值
  • 你不需要在状态中存储 isDisabled,你可以从 formik.submitCountformik.isSubmitting
  • 派生它
const Note = () => {
  const [showFrame, setShowFrame] = useState({ 1: true });
  const onCorrectSubmission = (frameId) => {
    setShowFrame({ ...showFrame, [frameId]: true });
  };

  const text =
    "What is the sum of the first three natural numbers? (give answer as a word, i.e one, two etc.)";
  const hint = "The first three natural numbers are 1, 2, and 3";
  const answer = "six";

  return (
    <div>
      <h1>Induction</h1>
      {showFrame[1] ? (
        <Frame
          id={1}
          text={text}
          hint={hint}
          answer={answer}
          onCorrectSubmission={onCorrectSubmission}
        />
      ) : null}
      {showFrame[2] ? (
        <Frame
          id={2}
          text={text}
          hint={hint}
          answer={answer}
          onCorrectSubmission={onCorrectSubmission}
        />
      ) : null}
    </div>
  );
};


const Frame = ({
  id,
  text,
  hint,
  answer,
  values,
  onCorrectSubmission,
  ...props
}) => {
  const validate = (values) => {
    const errors = {};
    if (!answer.startsWith(values.cloze)) {
      errors.cloze = hint;
    } else if (values.cloze !== answer) {
      errors.cloze = true;
    }
    return errors;
  };

  const formik = useFormik({
    initialValues: {
      cloze: ""
    },
    validate,
    onSubmit: (values) => {
      onCorrectSubmission(id + 1);
    }
  });

  const isFinished = formik.isSubmitting || formik.submitCount > 0;

  return (
    <form enablereinitialize={true} onSubmit={formik.handleSubmit}>
      <p>{text}</p>
      <input
        id="cloze"
        name="cloze"
        type="text"
        autoComplete="off"
        {...formik.getFieldProps("cloze")}
        disabled={isFinished}
        className={`input
           ${!answer.startsWith(formik.values.cloze) ? "invalid-input" : ""}
           ${formik.values.cloze && !formik.errors.cloze ? "valid-input" : ""}
        `}
      />
      {formik.values.cloze && formik.errors.cloze ? (
        <div>{formik.errors.cloze}</div>
      ) : null}
      <button disabled={!!formik.errors.cloze || isFinished} type="submit">
        Submit
      </button>
    </form>
  );
};

export default Frame;

Live Demo