React多步骤注册表单:输入框onChange后State被重置的解决方法
问题描述
开发多步骤注册表单时,将表单数据存储在registerData状态中,但输入内容时(例如Page1的姓名输入框),onChange会短暂更新对应字段,随后registerData立刻恢复为所有属性为空的初始状态。
相关代码
Register.js
import React, {useState} from 'react'; import Page1 from './register_components/Page1'; import Page2 from './register_components/Page2'; import Page3 from './register_components/Page3'; function Register() { const [registerData, setRegisterData] = useState( { //Personal Details Name: "", LastName: "", Phone: "", //Null Birthday: "", //Null //Address Street: "", Zip: "", Building: "", House: "", //Null City: "", Voivodeship: "", //Login information Email: "", Password: "" } ) const [ pageIndex, setPageIndex] = useState(0) const [ pages, setPages ] = useState([ <Page1 registerData={registerData} setRegisterData={(data) => {setRegisterData(data)}}/>, <Page2 registerData={registerData} setRegisterData={(data) => {setRegisterData(data)}}/>, <Page3 registerData={registerData} setRegisterData={(data) => {setRegisterData(data)}}/> ]) const PrevPage = () =>{ if (pageIndex <= 0) return setPageIndex(pageIndex - 1) } const HandleSubmit = (event) => { event.preventDefault(); if (pageIndex !== pages.length - 1){ setPageIndex(pageIndex + 1) return } console.log("Submmited") } return ( <div className="App"> <h1>Rejestracja</h1> <form className='register-form' onSubmit={HandleSubmit}> {pages[pageIndex]} {pageIndex !== 0 && <button type="button" onClick={ () => {PrevPage()}}>Poprzedni</button>} <button type="submit">{pageIndex !== pages.length -1? "Nastepny" : "Przeslij"}</button> </form> </div> ); } export default Register;
Page1.js
import React from 'react' export default function Page1({registerData, setRegisterData}) { console.log("rerender") console.log(registerData) return ( <div> <input placeholder='Imie' required type='text' value={registerData.Name} onChange={(e) => { setRegisterData({...registerData, Name: e.target.value}); console.log(e.target.value) }} /> <input placeholder='Nazwisko' required type='text' value={registerData.LastName} onChange={(e) => { setRegisterData({...registerData, LastName: e.target.value}) }} /> <input placeholder='Nr telefonu' required type='text' value={registerData.Phone} onChange={(e) => { setRegisterData({...registerData, Phone: e.target.value}) }} /> <div className='date-form'> <label>Data urodzenia</label> <input type='date' value={registerData.Date} onChange={e => { setRegisterData({...registerData, Birthday: e.target.value}) }} /> </div> </div> ) }
问题原因
- 你把页面组件实例存在了
pages这个useState中,初始渲染时这些组件拿到的是registerData的初始值。当registerData更新触发Register组件重渲染时,pages状态并未更新,依然保存着旧的组件实例,这些旧实例使用的还是初始的registerData,导致显示内容回退。 - Page1中生日输入框的
value绑定错误,写成了registerData.Date,但状态中对应的字段是Birthday,会导致输入的生日无法正确显示。
修复方案
1. 移除存储页面组件的pages状态,动态渲染页面组件
不需要把页面组件存在state里,每次渲染时根据pageIndex直接渲染对应组件,保证组件拿到最新的registerData和setRegisterData。
2. 修正Page1中生日输入框的value绑定
将value={registerData.Date}改为value={registerData.Birthday}。
修改后的代码
调整后的Register.js
import React, {useState} from 'react'; import Page1 from './register_components/Page1'; import Page2 from './register_components/Page2'; import Page3 from './register_components/Page3'; function Register() { const [registerData, setRegisterData] = useState( { //Personal Details Name: "", LastName: "", Phone: "", Birthday: "", //Address Street: "", Zip: "", Building: "", House: "", City: "", Voivodeship: "", //Login information Email: "", Password: "" } ) const [ pageIndex, setPageIndex] = useState(0) const PrevPage = () =>{ if (pageIndex <= 0) return setPageIndex(pageIndex - 1) } const HandleSubmit = (event) => { event.preventDefault(); if (pageIndex !== 2){ // 总共有3个页面,索引为0、1、2 setPageIndex(pageIndex + 1) return } console.log("Submmited", registerData) } // 根据当前页码渲染对应页面 const renderCurrentPage = () => { switch(pageIndex) { case 0: return <Page1 registerData={registerData} setRegisterData={setRegisterData}/> case 1: return <Page2 registerData={registerData} setRegisterData={setRegisterData}/> case 2: return <Page3 registerData={registerData} setRegisterData={setRegisterData}/> default: return null } } return ( <div className="App"> <h1>Rejestracja</h1> <form className='register-form' onSubmit={HandleSubmit}> {renderCurrentPage()} {pageIndex !== 0 && <button type="button" onClick={PrevPage}>Poprzedni</button>} <button type="submit">{pageIndex !== 2? "Nastepny" : "Przeslij"}</button> </form> </div> ); } export default Register;
调整后的Page1.js
import React from 'react' export default function Page1({registerData, setRegisterData}) { return ( <div> <input placeholder='Imie' required type='text' value={registerData.Name} onChange={(e) => { setRegisterData({...registerData, Name: e.target.value}) }} /> <input placeholder='Nazwisko' required type='text' value={registerData.LastName} onChange={(e) => { setRegisterData({...registerData, LastName: e.target.value}) }} /> <input placeholder='Nr telefonu' required type='text' value={registerData.Phone} onChange={(e) => { setRegisterData({...registerData, Phone: e.target.value}) }} /> <div className='date-form'> <label>Data urodzenia</label> <input type='date' value={registerData.Birthday} onChange={e => { setRegisterData({...registerData, Birthday: e.target.value}) }} /> </div> </div> ) }
内容的提问来源于stack exchange,提问作者MaciejT
相关产品推荐
相关产品推荐

