如何从外部控制Formik表单的输入元素?
从Formik外部控制表单输入的完整方案
为啥原生改值会被重置?
Formik是受控组件,所有表单输入的状态都由它内部维护。你直接用原生DOM改输入框的value,只是改了页面上的显示,没同步到Formik的内部状态。等Formik下次渲染(比如校验触发、其他字段更新),就会用自己存的状态把DOM值覆盖掉,所以你设的内容会被重置。
方案一:用innerRef拿Formik实例(类组件用这个最方便)
你已经用到了innerRef,其实可以通过它直接拿到Formik的实例,然后调用官方提供的setFieldValue方法来改值,这才是正确的姿势。
具体步骤:
- 在你的表单组件里定义一个ref,用来存Formik实例:
class SymptomForm extends React.Component { // 定义ref存Formik实例 formikRef = React.createRef(); // 写一个供外部调用的方法,比如语音转文本完成后调用 updateFormField = (fieldName, value) => { if (this.formikRef.current) { // 调用Formik的setFieldValue,自动同步状态和DOM this.formikRef.current.setFieldValue(fieldName, value); } }; submitMyForm = (values) => { // 你的提交逻辑 console.log(values); }; render() { return ( <Formik initialValues={{ describe_your_symptoms_here: '' }} validationSchema={/* 你的校验规则,比如Yup的Schema */} onSubmit={this.submitMyForm} // 把Formik实例挂载到我们的ref上 innerRef={this.formikRef} > {({ values, handleChange }) => ( <form> <input type="text" name="describe_your_symptoms_here" value={values.describe_your_symptoms_here} onChange={handleChange} placeholder="描述你的症状" /> {/* 其他表单元素 */} <button type="submit">提交</button> </form> )} </Formik> ); } }
- 在外部逻辑(比如语音转文本的回调)里,拿到表单组件的实例,调用
updateFormField:
// 假设语音转文本得到了结果 const voiceResult = "Roger Rabbit"; // 假设你通过ref拿到了SymptomForm的实例 symptomFormRef.current.updateFormField("describe_your_symptoms_here", voiceResult);
方案二:用Formik Context(跨组件层级时用)
如果你的语音控制逻辑和表单不在同一个组件里,或者层级比较深,可以用Formik的Context来获取实例。
具体步骤:
- 写一个语音控制的组件,消费Formik的Context:
import { FormikContext } from 'formik'; import React from 'react'; const VoiceInputButton = () => { // 从Context里拿Formik实例 const formik = React.useContext(FormikContext); const handleVoiceInput = async () => { // 这里写你的语音转文本逻辑,假设拿到结果voiceText const voiceText = "Roger Rabbit"; if (formik) { formik.setFieldValue("describe_your_symptoms_here", voiceText); } }; return <button onClick={handleVoiceInput}>语音输入症状</button>; };
- 把这个语音组件放在Formik的内部,确保能拿到Context:
<Formik initialValues={{ describe_your_symptoms_here: '' }} validationSchema={/* 你的校验规则 */} onSubmit={this.submitMyForm} > {({ values, handleChange }) => ( <div> <form> <input type="text" name="describe_your_symptoms_here" value={values.describe_your_symptoms_here} onChange={handleChange} placeholder="描述你的症状" /> <button type="submit">提交</button> </form> {/* 语音按钮放在Formik内部,才能拿到Context */} <VoiceInputButton /> </div> )} </Formik>
顺便说下:怎么给Formik的form标签加id
你之前给Formik组件加id没用,因为Formik不会把自身的props传给内部的form标签。要给form加id,得在render回调里手动写:
<Formik // ...其他props > {() => ( <form id="myform3"> {/* 表单元素 */} </form> )} </Formik>
这样你就能用document.getElementById("myform3")拿到form了,但还是不建议用原生DOM改值,用上面的Formik API才是稳定的方式。
内容的提问来源于stack exchange,提问作者The Old County
相关产品推荐
相关产品推荐

