Ana*_*oly 9 reactjs yup formik
我想异步验证用户输入。例如,检查电子邮件是否已存在,并在用户键入时执行验证。为了减少 API 调用,我想使用 lodash 或自定义去抖函数来去抖 API 调用,并在用户停止输入时执行验证。
到目前为止,这就是我的表格。问题是它没有按预期工作。看来被谴责的函数返回了上一次调用的值,我不明白问题出在哪里。
您可以在这里看到一个实例: https: //codesandbox.io/s/still-wave-qwww6
import { isEmailExists } from "./api";
const debouncedApi = _.debounce(isEmailExists, 300, {
trailing: true
});
export default function App() {
const validationSchema = yup.object({
email: yup
.string()
.required()
.email()
.test("unique_email", "Email must be unique", async (email, values) => {
const response = await debouncedApi(email);
console.log(response);
return response;
})
});
const formik = useFormik({
initialValues: {
email: ""
},
validateOnMount: true,
validationSchema: validationSchema,
onSubmit: async (values, actions) => {}
});
return (
<form onSubmit={formik.handleSubmit}>
<label>
Email:
<input
type="text"
name="email"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.email}
/>
<div className="error-message">{formik.errors.email}</div>
</label>
</form>
);
}
Run Code Online (Sandbox Code Playgroud)
我使用以下函数模拟 API 调用:
export const isEmailExists = async email => {
return new Promise(resolve => {
console.log('api call', email);
setTimeout(() => {
if (email !== 'test@gmail.com') {
return resolve(true);
} else {
return resolve(false);
}
}, 200);
})
}
Run Code Online (Sandbox Code Playgroud)
更新:尝试编写我自己的去抖函数实现。这样,最后一个 Promise 的解析将被保留到超时,只有那时函数才会被调用,Promise 才会被解析。
const debounce = func => {
let timeout;
let previouseResolve;
return function(query) {
return new Promise(async resolve => {
//invoke resolve from previous call and keep current resolve
if (previouseResolve) {
const response = await func.apply(null, [query]);
previouseResolve(response);
}
previouseResolve = resolve;
//extending timeout
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
timeout = setTimeout(async () => {
const response = await func.apply(null, [query]);
console.log('timeout expired', response);
previouseResolve(response);
timeout = null;
}, 200);
})
}
}
const debouncedApi = debounce(isEmailExists);
const validationSchema = yup.object({
email: yup
.string()
.required()
.email()
.test('unique_email', 'Email must be unique', async (email, values) => {
const response = await debouncedApi(email);
console.log('test response', response);
return response;
})
});
Run Code Online (Sandbox Code Playgroud)
不幸的是,它也不起作用。看起来是的,当下一次调用发生时,会中止未解析的函数调用。当我打字快时,它不起作用,当我打字慢时,它起作用。您可以在此处查看更新的示例:https ://codesandbox.io/s/suspicious-chaum-0psyp
看来被谴责的函数返回了上一次调用的值
这就是 lodash debounce 的工作原理:
对去抖函数的后续调用将返回最后一次 func 调用的结果。
请参阅: https: //lodash.com/docs/4.17.15#debounce
您可以设置validateOnChange
为false
然后formik.validateForm
手动调用作为副作用:
import debounce from 'lodash/debounce';
import { isEmailExists } from "./api";
const validationSchema = yup.object({
email: yup
.string()
.required()
.email()
.test("unique_email", "Email must be unique", async (email, values) => {
const response = await isEmailExists(email);
console.log(response);
return response;
})
});
export default function App() {
const formik = useFormik({
initialValues: {
email: ""
},
validateOnMount: true,
validationSchema: validationSchema,
validateOnChange: false, // <--
onSubmit: async (values, actions) => {}
});
const debouncedValidate = useMemo(
() => debounce(formik.validateForm, 500),
[formik.validateForm],
);
useEffect(
() => {
console.log('calling deboucedValidate');
debouncedValidate(formik.values);
},
[formik.values, debouncedValidate],
);
return (
...
);
}
Run Code Online (Sandbox Code Playgroud)
这样,整个验证将被反跳,而不仅仅是远程调用。
如果没有依赖关系,最好将架构放在组件之外,但在每次渲染中执行此操作通常很慢。
归档时间: |
|
查看次数: |
8319 次 |
最近记录: |