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
尽可能小,它仅用于访问输入值,因此不需要将 hint
和 answer
分配给它
- 验证函数的目的是 return 一个
errors
对象而不是设置值,所以删除像 values.correct = true
这样的赋值
- 你不需要在状态中存储
isDisabled
,你可以从 formik.submitCount
和 formik.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;
我正在尝试使用 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
尽可能小,它仅用于访问输入值,因此不需要将hint
和answer
分配给它 - 验证函数的目的是 return 一个
errors
对象而不是设置值,所以删除像values.correct = true
这样的赋值
- 你不需要在状态中存储
isDisabled
,你可以从formik.submitCount
和formik.isSubmitting
派生它
values
而不是 touched
更简单
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;