React中Formik onChange不触发及跨组件表单值同步问题
问题解决方案
问题1:输入框onChange无输出、initVal.q4不更新的修复
- 自定义onChange被覆盖:你在Input中先声明了自定义
onChange,随后用{...field}引入Formik的field对象,而field自带的onChange会覆盖你的自定义逻辑,导致控制台无输出。要保留自定义行为,需将两者结合执行。 - initVal非响应式状态:
initVal是普通变量,组件重新渲染时会被重新初始化,无法追踪输入框的内容变化。需要用React的useState来管理q4的值,确保响应式更新。
修复后的Input代码:
<Input borderRadius={0} id="q4" h="50px" p="1" {...field} onChange={(e) => { // 先执行Formik的onChange更新表单状态 field.onChange(e); // 再执行自定义打印逻辑 console.log(e.target.value); }} placeholder="Please input your answer"/>
改造Part4的状态管理:
import React, { useState } from 'react'; import { Box, Input, Text, Flex, Button, Heading, Grid, GridItem, } from '@chakra-ui/react'; import { Field, Formik, Form } from 'formik'; import KPIForm from '../KPIForm'; import ButtonGroup from '../ButtonGroup'; export default function Part4({ values, setPage}) { // 用useState管理q4的值,初始化时从props.values读取 const [q4Value, setQ4Value] = useState(values ? values.q4.answers[0] : ''); const initVal = { q4: q4Value, q5: { a1: ['', { value: 0, unit: '%' }, { value: 0, unit: '%' }, { value: 0, unit: '%' }, { value: 0, unit: '%' }], a2: ['', { value: 0, unit: '($)' }, { value: 0, unit: '($)' }, { value: 0, unit: '($)' }, { value: 0, unit: '($)' }], } }; if(values){ const { q5 } = values; initVal.q5 = q5.answers; initVal.q5.a1 = q5.answers.a1; initVal.q5.a2 = q5.answers.a2; } return ( <> <Box bg={'white'} p="4"> <Formik enableReinitialize initialValues={{q4: q4Value}} // 监听Formik值变化,同步更新外部state onValuesChange={(newValues) => setQ4Value(newValues.q4)} > {(props) => ( <Form> <Heading as="h3" size={'sm'} paddingBottom="5"> 4. Of all your PERSONAL priorities, what do you want to achieve most in the next 90 days? </Heading> <Box mb={10}> <Field name="q4" type="text"> {({field, form, meta}) => ( <Input borderRadius={0} id="q4" h="50px" p="1" {...field} onChange={(e)=>{ field.onChange(e); console.log(e.target.value); }} placeholder="Please input your answer"/> )} </Field> </Box> <br/> <Heading as="h3" size={'sm'} paddingBottom="5"> 5. Now think about how to measure this. What is the best result you think deserves a reward remembering, anything greater than 80% should be rewarded. </Heading> </Form> )} </Formik> {/* 传递包含最新q4的initValues给KPIForm */} <KPIForm initValues={{...initVal, q4: q4Value}} pageNo={4} setPage={setPage}/> </Box> </> ); }
问题2:让KPIForm实时获取q4更新值
通过上述改造,q4Value会实时同步Formik中q4的输入值,传递给KPIForm后,只需在KPIForm中监听initValues的变化即可拿到最新q4:
KPIForm中监听更新:
export default function KPIForm({ initValues, pageNo, setPage }) { const { contextValue, setProgress, updateSection, setSection } = useContext(SectionsContext); const { quickStart, rewardsCelebrations, strengthsOpportunities, visionOfSuccess, numbers, } = contextValue; const progress = rewardsCelebrations.progress; let initVal = pageNo == 2 ? initValues : initValues.q5; useEffect(()=>{ console.log('最新的q4值:', initValues.q4); // 在这里处理q4更新后的逻辑 }, [initValues]) return ( <> <Box> ........ </> ); }
更简洁的方式:单独传递q4 props
如果不需要传递整个initValues,可以直接把q4作为单独props传入,监听更精准:
// Part4中传递 <KPIForm q4={q4Value} initValues={initVal} pageNo={4} setPage={setPage}/> // KPIForm中接收并监听 export default function KPIForm({ q4, initValues, pageNo, setPage }) { const { contextValue, setProgress, updateSection, setSection } = useContext(SectionsContext); const { quickStart, rewardsCelebrations, strengthsOpportunities, visionOfSuccess, numbers, } = contextValue; const progress = rewardsCelebrations.progress; let initVal = pageNo == 2 ? initValues : initValues.q5; useEffect(()=>{ console.log('最新的q4值:', q4); // 后续处理逻辑 }, [q4]) return ( <> <Box> ........ </> ); }
内容的提问来源于stack exchange,提问作者Shotto
相关产品推荐
相关产品推荐

