我正在尝试将 Formik 与 React 的
useRef
钩子结合使用来创建对我的表单的引用,然后我可以在该表单之外访问该引用。但是,无论我做什么,引用中的值都不会像我期望的那样更新。
我创建了一个小示例来演示该问题。
import React, { useEffect, useRef, useMemo } from "react";
import { render } from "react-dom";
import { Formik } from "formik";
const App = () => {
const formRef = useRef();
useEffect(() => {
console.log("formRef changed", formRef.current);
}, [formRef]);
const email = useMemo(() => {
if (formRef.current) {
const email = formRef.current.values;
return email;
}
return "<none>";
}, [formRef.current?.values]); //This dependency array was a test, I tried formRef and formRef.current separately aswell.
return (
<div className="app">
<Formik
innerRef={(f) => (formRef.current = f)}
initialValues={{ email: "[email protected]" }}
onSubmit={(values) => {
console.log(values);
}}
>
{(props) => {
const {
values,
isSubmitting,
handleChange,
handleReset,
handleSubmit
} = props;
return (
<form onSubmit={handleSubmit}>
<label htmlFor="email" style={{ display: "block" }}>
Email
</label>
<input
id="email"
placeholder="Enter your email"
type="text"
value={values.email}
onChange={handleChange}
/>
<button type="button" className="outline" onClick={handleReset}>
Reset
</button>
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</form>
);
}}
</Formik>
<span>Entered e-mail: {email}</span>
</div>
);
};
render(<App />, document.getElementById("root"));
不幸的是,我无法让它与 Stack Snippets 一起使用,所以我制作了一个codesandbox: https://codesandbox.io/s/formik-example-forked-0osy6?file=/index.js
我最初想这样做,因为我需要这个值在与表单完全无关的地方。我考虑过只使用状态变量,但这感觉像是不必要地重复状态,但我可能是错的。
非常感谢!
useRef 无法通知,无法重新渲染 React 组件。 要重新渲染页面,您需要在值更新时使用 useState 来更新组件。
而不是使用
const formRef = useRef();
const [values, setValues] = useState({});
在 Formik 中替换
innerRef={(f) => (formRef.current = f)}
与:innerRef={(formikActions) => (formikActions? setValues(formikActions.values) : setValues({})}
现在你可以更新 useEffect 来监听值状态,因此更改将始终被监听。
useEffect(() => {
console.log("values changed", values);
}, [values]);
反应
useRef
无法随着状态变化而更新。如果您需要这些值,则无法更新,您必须尝试其他方法,或者使用 Formik useField
来获取您要使用的字段的值。
您完全可以通过使用 Ref. 从其他地方访问 Formik 的值。在这里,当我为提交按钮添加回调时,您可以看到值已更新。
// Helper styles for demo
import "./helper.css";
import React, { useEffect, useRef, useState } from "react";
import { render } from "react-dom";
import { Formik } from "formik";
const App = () => {
const formRef = useRef();
const [email, setEmail] = useState("");
useEffect(() => {
console.log("formRef changed", formRef.current);
}, [formRef]);
const submitForm = () => {
setEmail(formRef.current.values.email);
};
const resetForm = () => {
formRef.current.resetForm();
};
// const email = useMemo(() => {
// if (formRef.current) {
// const email = formRef.current.values;
// return email;
// }
// return "<none>";
// }, [formRef.current?.values]);
return (
<div className="app">
<Formik
enableReinitialize
innerRef={(f) => (formRef.current = f)}
initialValues={{ email: "[email protected]" }}
onSubmit={(values) => {
console.log(values);
}}
>
{(props) => {
const {
values,
isSubmitting,
handleChange,
handleReset,
handleSubmit
} = props;
return (
<form onSubmit={handleSubmit}>
<label htmlFor="email" style={{ display: "block" }}>
Email
</label>
<input
id="email"
placeholder="Enter your email"
type="text"
value={values.email}
onChange={handleChange}
/>
<button type="button" className="outline" onClick={resetForm}>
Reset
</button>
<button disabled={isSubmitting} onClick={submitForm}>
Submit
</button>
</form>
);
}}
</Formik>
<span>Entered e-mail: {email}</span>
</div>
);
};
render(<App />, document.getElementById("root"));
沙盒中的工作代码在这里 https://codesandbox.io/s/formik-example-forked-7nxcni?file=/index.js
此外,您还可以将 ref 放在父组件中并将其传递给子组件。检查这个沙箱,https://codesandbox.io/s/formik-example-forked-pfri64?file=/index.js