如何在React的Formik表单中从URL提取邮箱地址与公司名称
核心问题说明
你当前的代码存在三个问题导致邮箱提取失败:
- Formik 默认仅在首次渲染时读取
initialValues,后续通过useEffect更新邮箱状态后,Formik 不会自动同步更新表单初始值 - URL 解析逻辑错误,你直接把
?后的所有内容作为邮箱,没有拆分后续的 campaign 参数,也没有正确提取公司名称 - React 的状态更新是异步的,
setEmail执行后立刻打印selectedemail.text无法拿到最新值,属于 React 正常的执行机制
修复方案
你可以直接在组件初始化阶段完成 URL 解析(不需要额外的 useEffect 和状态存储),同时给 Formik 开启 enableReinitialize 配置适配动态初始值,适配你给出的固定URL格式的完整代码如下:
// @ts-ignore import React, { useState } from 'react'; import { Formik, Form, Field } from 'formik'; import { Typography, Button, Grid } from '@material-ui/core'; import * as Yup from 'yup'; import { MyInput } from './comman/MyInput'; import { Textarea } from './comman/Textarea'; import { Event } from '../Tracking/Event'; const contactSchema = Yup.object().shape({ name: Yup.string().required('Please Enter Your Name'), email: Yup.string() .email('Please enter a valid email address') .required('Please enter an email address'), number: Yup.string() .min(10, 'Must be 10 digit.') .max(10, 'Must be 10 digit.'), }); export default function ContactUs(props: any) { const [state, setState] = useState({ msg: '', }); // 新增:直接解析URL获取邮箱和公司名,适配你给出的URL格式 const queryStr = window.location.href.split('?')[1] || ''; const queryParts = queryStr.split('&'); // 提取邮箱:?后第一个&前的内容就是邮箱 const initEmail = queryParts[0] || ''; // 提取公司名:从abccampaign参数里按%拆分取第三段 let initCompany = ''; if (queryParts[1]) { const campaignParts = queryParts[1].split('=')[1]?.split('%') || []; initCompany = campaignParts[2] || ''; } return ( <div> <img src="public/abc.png" width="200" className="d-inline-block" alt="Viser" style={{ marginTop: '2em', marginBottom: '2em', float: 'right', }} /> {/* 新增enableReinitialize配置,允许动态更新初始值 */} <Formik enableReinitialize={true} initialValues={{ name: '', email: initEmail, number: '', companyname: initCompany, message: '', }} validationSchema={contactSchema} onSubmit={(values, { resetForm }) => { const data = { name: values.name, email: values.email, number: values.number, companyname: values.companyname, message: values.message, formtype: 'Contactus', }; console.log(data); const request = new Request( `${process.env.REACT_APP_PRODUCTION_EMAILCONTACTUS_API}`, { method: 'POST', headers: new Headers({ 'Content-Type': 'application/json', }), body: JSON.stringify(data), }, ); fetch(request) .then((res) => res.json()) .then((data) => { if (data.message === 'Thanks!') { setState({ msg: data.message, }); } else { console.log('error'); } }); resetForm(); }} > {({ errors, touched }) => ( <Grid container> <Grid item xs={12}> <Typography variant="body1" style={{ marginTop: '1em', fontFamily: 'roboto', fontSize: '1.3rem', color: '#2F4858', }} > To know more please submit your information, and one of our expert advisors will get in touch within 24 hours! </Typography> <br /> <Form> <Typography variant="h6" style={{ fontFamily: 'roboto', color: '#2F4858', marginTop: '0.5em', }} > Full Name </Typography> <Field id="outlined-multiline-flexible" type="text" name="name" placeholder="Name" component={MyInput} /> <br /> {errors.name && touched.name ? ( <div className="text-danger" style={{ color: 'red' }}> {errors.name} </div> ) : null} <Typography variant="h6" style={{ fontFamily: 'roboto', marginTop: '1em' }} > Email </Typography> <Field type="email" name="email" placeholder="Email" style={{ color: 'white' }} component={MyInput} /> <br /> {errors.email && touched.email ? ( <div className="text-danger" style={{ color: 'red' }}> {errors.email} </div> ) : null} <Typography variant="h6" style={{ fontFamily: 'roboto', color: '#2F4858', marginTop: '1em', }} > Mobile Number (Optional) </Typography> <Field name="number" placeholder="Contact Number" component={MyInput} /> <br /> {errors.number && touched.number ? ( <div className="text-danger" style={{ color: 'red' }}> {errors.number} </div> ) : null} <Typography variant="h6" style={{ fontFamily: 'roboto', color: '#2F4858', marginTop: '1em', }} > Company Name (Optional) </Typography> <Field name="companyname" placeholder="Company Name" component={MyInput} /> <br /> <Typography variant="h6" style={{ fontFamily: 'roboto', color: '#2F4858', marginTop: '1em', }} > How can we help? (Optional) </Typography> <Field id="outlined-multiline-static" name="message" placeholder="Your question about our services" label="How can we help?" component={Textarea} /> <br /> <br /> <Button type="submit" variant="contained" style={{ background: '#F79924', color: 'white', fontFamily: 'roboto', fontSize: '1rem', }} > Submit </Button> <br /> {state.msg && ( <Typography variant="h6" style={{ color: '#4BB543', fontFamily: 'roboto-medium', marginTop: '1em', }} > {state.msg} </Typography> )} </Form> </Grid> </Grid> )} </Formik> </div> ); }
改动说明
- 删掉了冗余的
selectedemail状态和对应的useEffect,直接在组件初始化时解析URL,减少不必要的状态更新 - 新增了适配你给出的URL格式的解析逻辑,同时提取邮箱和公司名,没有对应参数时默认返回空字符串
- 给Formik新增了
enableReinitialize={true}配置,如果你后续需要动态修改初始值也可以正常生效 - 删掉了Field组件里无效的
values={props.text}属性,避免干扰Formik的默认值逻辑
内容的提问来源于stack exchange,提问作者sudesh sharma
相关产品推荐
相关产品推荐

