React组件输入时重复渲染失焦问题及优化方案咨询
问题与解决方案
问题描述
每次输入字符后,BetterInputGroup组件都会重新渲染。疑惑是否因将BetterInputGroup定义在AddTask组件内部所致?若将其移至外部文件,则无法访问formData状态与handleFormChange方法。请问是否存在更优实现方式?
相关代码:
const AddTask = () => { const [formData, setFormData] = useState({ data: {taskname: "", department: "", frequency: -1, subtasks: [{name: "", description: "", inputtype: 0, inputprefix: ""}]}, validity: {taskname: false, department: false, frequency: false, subtasks: [{name: false, inputtype: false}]} }) const BetterInputGroup = ({sidetext, styledata, pathtodata}) => { const pathList = pathtodata.split(".") let compValid = pathList.length > 1 ? formData["validity"][pathList[0]][pathList[1]] : formData["validity"][pathtodata] let compValue = pathList.length > 1 ? formData["data"][pathList[0]][pathList[1]] : formData["data"][pathtodata] return ( <CInputGroup className={styledata}> <CInputGroupText>{sidetext}</CInputGroupText> <CFormInput type="text" value={compValue} onChange={e => {handleFormChange(e, pathtodata)}} valid={compValid} invalid={!compValid}/> </CInputGroup> ) } const handleFormChange = (event, path) => { let newFormData = {...formData} const pathList = path.split(".") if(pathList === "subtasks") { newFormData["data"]["subtasks"][pathList[1]][pathList[2]] = event.target.value if(newFormData["validity"]["subtasks"][pathList[1]][pathList[2]] != null) { // newFormData["validity"]["subtasks"][pathList[1]][pathList[2]] = regexes["subtasks"][pathList[2]].test(event.target.value) } } else { newFormData["data"][pathList[0]] = event.target.value newFormData["validity"][pathList[0]] = regexes[pathList[0]].test(event.target.value) } setFormData(newFormData) } const regexes = {taskname: /[a-zA-Z\s]+$/, department: /[1-9]$/, frequency: /^(?:[1-9]\d?|[12]\d{2}|3[0-5]\d|36[0-5])$/, sutasks: {name: /[a-zA-Z\s]{20}$/, inputtype: /[1-9]$/}} return ( <> <BetterInputGroup styledata="w-auto p-3 has-validation" sidetext="Task name" pathtodata="taskname" /> </> ) }
优化方案
1. 内部定义组件导致频繁重渲染的原因
你判断的完全正确:把BetterInputGroup定义在AddTask内部时,每次AddTask重渲染(比如formData更新),都会生成一个全新的组件类型。React会将其识别为不同组件,销毁旧实例并重新挂载新实例,最终表现为每次输入都触发完全重渲染。
2. 抽离组件+传递必要props的最优实现
将BetterInputGroup移到外部文件,通过props直接传递它需要的value、valid状态和onChange回调,而非让它依赖父组件内部状态。这样组件既能独立复用,也不会被父组件重渲染影响。
抽离后的BetterInputGroup.jsx
import { CInputGroup, CInputGroupText, CFormInput } from '@coreui/react'; const BetterInputGroup = ({ sidetext, styledata, value, valid, onChange }) => { return ( <CInputGroup className={styledata}> <CInputGroupText>{sidetext}</CInputGroupText> <CFormInput type="text" value={value} onChange={onChange} valid={valid} invalid={!valid} /> </CInputGroup> ) } export default BetterInputGroup;
修改后的AddTask组件
import { useState } from 'react'; import BetterInputGroup from './BetterInputGroup'; const AddTask = () => { const [formData, setFormData] = useState({ data: {taskname: "", department: "", frequency: -1, subtasks: [{name: "", description: "", inputtype: 0, inputprefix: ""}]}, validity: {taskname: false, department: false, frequency: false, subtasks: [{name: false, inputtype: false}]} }) const handleFormChange = (event, path) => { // 修复:浅拷贝无法更新嵌套对象,改用深拷贝避免状态突变 const newFormData = JSON.parse(JSON.stringify(formData)); const pathList = path.split("."); // 修复:原判断逻辑错误,pathList是数组需取第一个元素判断 if (pathList[0] === "subtasks") { const [_, index, field] = pathList; newFormData.data.subtasks[index][field] = event.target.value; if (newFormData.validity.subtasks[index][field] != null) { newFormData.validity.subtasks[index][field] = regexes.subtasks[field].test(event.target.value); } } else { const [field] = pathList; newFormData.data[field] = event.target.value; newFormData.validity[field] = regexes[field].test(event.target.value); } setFormData(newFormData); } // 修复:原拼写错误sutasks → subtasks const regexes = { taskname: /[a-zA-Z\s]+$/, department: /[1-9]$/, frequency: /^(?:[1-9]\d?|[12]\d{2}|3[0-5]\d|36[0-5])$/, subtasks: {name: /[a-zA-Z\s]{20}$/, inputtype: /[1-9]$/} } return ( <> <BetterInputGroup styledata="w-auto p-3 has-validation" sidetext="Task name" value={formData.data.taskname} valid={formData.validity.taskname} onChange={(e) => handleFormChange(e, "taskname")} /> {/* 其他输入组件示例,如部门选择 */} {/* <BetterInputGroup styledata="w-auto p-3 has-validation" sidetext="Department" value={formData.data.department} valid={formData.validity.department} onChange={(e) => handleFormChange(e, "department")} /> */} </> ) } export default AddTask;
3. 额外优化:减少不必要重渲染
如果想让BetterInputGroup仅在props变化时重渲染,可用React.memo包裹组件:
import { memo } from 'react'; const BetterInputGroup = memo(({ sidetext, styledata, value, valid, onChange }) => { // 组件内容不变 })
内容的提问来源于stack exchange,提问作者Quib
相关产品推荐
相关产品推荐

