You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 23:50:30