React Hook Form中blockquote输入后验证提示不消失,求技术指导
React Hook Form 配合 contentEditable blockquote 验证不更新的问题解决
问题根源
- 非标准表单控件不兼容
register:blockquote不是原生表单元素,即使加上contentEditable='true',React Hook Form的register方法也无法自动监听它的输入变化、同步值,导致验证状态无法实时更新。 - 重复字段名冲突:多个
blockquote都注册为blogcode,RHF无法区分不同输入项,字段值会被相互覆盖,验证逻辑混乱。 contentEditable不支持value属性:你给blockquote设置的value属性无效,原生contentEditable元素的内容是通过innerText/innerHTML控制的。
解决方案
用React Hook Form的Controller组件手动管控非标准表单控件,同时调整字段命名为数组格式区分多个输入项:
1. 导入Controller
首先在顶部导入Controller:
import { useForm, Controller } from "react-hook-form";
2. 修改字段注册与渲染逻辑
替换原来的map渲染部分,用Controller包裹blockquote,并使用数组字段名:
const { control, formState: { errors } } = useForm(); <div className='row'> {createCode.map((code, idx) => { const fieldName = `blogcode[${idx}]`; // 用数组索引区分每个字段 return ( <div key={`${code}-${idx}`} className="dCodeArea"> <button type="button" onClick={() => handleRemoveCode(idx)} className="closeElement"> X </button> <Controller name={fieldName} control={control} rules={{ required: "Blog code is required !", minLength: { value: 5, message: "Minimum length of code is 5" } }} render={({ field: { onChange, value } }) => ( <blockquote contentEditable='true' className="codehighlight" onInput={(e) => onChange(e.currentTarget.innerText)} // 手动触发onChange同步值 dangerouslySetInnerHTML={{ __html: value || "" }} // 用dangerouslySetInnerHTML设置内容 placeholder="Enter your code here" /> )} /> <span className="validationmsg"> {errors.blogcode?.[idx] && <span>{errors.blogcode[idx].message}</span>} </span> </div> ); })} </div>
3. 进阶优化:用useFieldArray管理动态输入项
如果需要动态添加/移除输入项,推荐用RHF的useFieldArray替代自己维护的createCode状态,更贴合RHF的逻辑:
const { control, formState: { errors }, useFieldArray } = useForm({ defaultValues: { blogcode: [""] // 默认一个空输入项 } }); const { fields, append, remove } = useFieldArray({ control, name: "blogcode" }); // 移除按钮直接调用remove(idx),添加按钮调用append("")
关键注意点
contentEditable元素的placeholder需要自定义样式实现,原生不支持,比如当内容为空时显示占位文本。- 使用
dangerouslySetInnerHTML时要注意XSS风险,如果输入内容是用户可控的,建议做转义处理。
内容的提问来源于stack exchange,提问作者soccerway
相关产品推荐
相关产品推荐

