使用Redux Toolkit存储表单数据:前端无显示且验证失效
问题描述
我正在开发一个使用Redux Toolkit将表单值存储到Redux Store的表单,能够在Redux DevTools中看到存储的数据,但输入的内容在表单中不显示,且输入字段的验证功能无法正常工作。
相关代码
userSlice.js
import { createSlice } from '@reduxjs/toolkit'; const initialState = { name: null, email: null, phone: null, url: null, message: null } export const userSlice = createSlice({ name: 'user', initialState, reducers: { saveUser: (state, action) => { state.name = action.payload?.name; state.email = action.payload?.email; state.phone = action.payload?.phone; state.url = action.payload?.url; state.message = action.payload?.message; } } }) export const { saveUser } = userSlice.actions; export default userSlice.reducer;
store.js
import { configureStore } from '@reduxjs/toolkit'; import userReducer from '../Slice/userSlice'; export const store = configureStore ({ reducer: { user: userReducer } });
Contact.js
import React from 'react'; import ContactForm from '../../Forms/ContactForm'; function Contact() { return( <div className="columns"> <ContactForm /> </div> ) } export default Contact;
ContactForm.js
import React, { useRef, useState } from 'react'; import { Field, reduxForm } from 'redux-form'; import { useDispatch } from 'react-redux'; import validate from '../Validations/validate'; import renderTextArea from '../Fields/TextAreaInput/renderTextArea'; import renderField from '../Fields/TextInput/renderField'; import './ContactForm.css'; import { saveUser } from '../Slice/userSlice'; function ContactForm() { const formContainer = useRef(null); const dispatch = useDispatch(); const [user, setUser] = useState({ name: null, email: null, phone: null, url: null, message: null }); const handleChange = e => { const { name, value } = e.target; setUser({ ...user, [name]: value }); console.log("user", user) } const handleSubmit = e => { console.log(user, "submit data") e.preventDefault(); dispatch(saveUser((user))); } return ( <div className="container"> <form id="contact" ref={formContainer} onSubmit={handleSubmit}> <h3>Contact Us</h3> <fieldset> <Field name="name" id="name" type="text" placeholder="Your full name" component={renderField} onChange={handleChange} /> </fieldset> <fieldset> <Field name="email" id="email" type="email" placeholder="Your email" component={renderField} onChange={handleChange} /> </fieldset> <fieldset> <Field name="phone" id="phone" type="text" placeholder="Your phone number" component={renderField} onChange={handleChange} /> </fieldset> <fieldset> <Field placeholder="Your Web Site" type="url" name="url" component={renderField} onChange={handleChange} /> </fieldset> <fieldset> <Field name="message" component={renderTextArea} id="message" placeholder="Enter your message here..." rows={4} onChange={handleChange} /> </fieldset> <fieldset> <button name="submit" type="submit" id="contact-submit">Submit</button> </fieldset> </form> </div> ) } export default reduxForm({ form: 'contact', validate, })(ContactForm);
validate.js
const validate = val => { const errors = {} if (!val.name) { errors.name = 'Required'; } else if(!/^[a-zA-Z ]+$/.test(val.name)) { errors.name = 'Invalid Name'; } if (!val.email) { errors.email = 'Required'; } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(val.email)) { errors.email = 'Invalid email address'; } if (!val.phone) { errors.phone = 'Required'; } else if (val.phone.length !== 10) { if(/[^0-9]/.test(val.phone)) { errors.phone = 'Phone number must be 10 characters' } else { errors.phone = 'Invalid phone number' } } if(!val.url) { val.url = !val.url ? "" : val.url; } if (!val.message) { val.message = !val.message ? "" : val.message; } return errors; } export default validate;
解决方案
核心问题
你同时混用了redux-form和本地useState管理表单状态,两者的状态同步逻辑冲突,导致输入不显示、验证失效。redux-form的<Field>组件本身会接管字段的状态管理,自定义的onChange和本地useState会干扰它的正常工作。
具体修复步骤
1. 移除本地状态和自定义 onChange
删除ContactForm.js中的useState声明、handleChange函数,同时移除所有<Field>组件上的onChange属性:
// 修改后的ContactForm.js核心部分 function ContactForm() { const formContainer = useRef(null); const dispatch = useDispatch(); // 调整提交逻辑,从redux-form获取表单值 const submitForm = (values) => { console.log(values, "submit data"); dispatch(saveUser(values)); }; return ( <div className="container"> {/* 用redux-form的handleSubmit包裹自定义提交函数 */} <form id="contact" ref={formContainer} onSubmit={handleSubmit(submitForm)}> <h3>Contact Us</h3> <fieldset> <Field name="name" id="name" type="text" placeholder="Your full name" component={renderField} /> </fieldset> <fieldset> <Field name="email" id="email" type="email" placeholder="Your email" component={renderField} /> </fieldset> <fieldset> <Field name="phone" id="phone" type="text" placeholder="Your phone number" component={renderField} /> </fieldset> <fieldset> <Field placeholder="Your Web Site" type="url" name="url" component={renderField} /> </fieldset> <fieldset> <Field name="message" component={renderTextArea} id="message" placeholder="Enter your message here..." rows={4} /> </fieldset> <fieldset> <button name="submit" type="submit" id="contact-submit">Submit</button> </fieldset> </form> </div> ) }
2. 修正validate.js逻辑
不要修改传入的val对象,仅处理错误提示:
const validate = val => { const errors = {}; if (!val.name) { errors.name = '必填项'; } else if(!/^[a-zA-Z ]+$/.test(val.name)) { errors.name = '无效姓名'; } if (!val.email) { errors.email = '必填项'; } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(val.email)) { errors.email = '无效邮箱地址'; } if (!val.phone) { errors.phone = '必填项'; } else if (val.phone.length !== 10) { if(/[^0-9]/.test(val.phone)) { errors.phone = '手机号必须是10位数字'; } else { errors.phone = '无效手机号'; } } // url和message为非必填项,无需处理,直接返回错误对象即可 return errors; }; export default validate;
3. 确保自定义字段组件正确接收redux-form props
redux-form的<Field>会把input(包含value、onChange等)和meta(包含验证状态)传给自定义组件,你的renderField和renderTextArea需要正确使用这些props:
// 示例renderField实现 const renderField = ({ input, placeholder, type, meta: { touched, error } }) => ( <div className="field-container"> <input {...input} type={type} placeholder={placeholder} /> {/* 显示验证错误 */} {touched && error && <span className="error-text">{error}</span>} </div> ); // 示例renderTextArea实现 const renderTextArea = ({ input, placeholder, rows, meta: { touched, error } }) => ( <div className="field-container"> <textarea {...input} placeholder={placeholder} rows={rows} /> {touched && error && <span className="error-text">{error}</span>} </div> );
验证效果
修复后:
- 输入内容会实时显示在表单字段中
- 字段失去焦点时会触发验证,错误提示正常显示
- 提交表单时,redux-form会先验证,通过后才会调用
submitForm,将正确的表单值存入Redux Store
内容的提问来源于stack exchange,提问作者Inspond
相关产品推荐
相关产品推荐

