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

React输入框因重渲染失焦,如何改为顶层函数实现?

解决动态树形组件输入框失焦问题

问题原因

当前createItemsFromTree是父组件内部的函数,每次父组件重渲染时该函数都会被重新定义,导致它返回的React元素被识别为全新组件,输入框因此失去焦点。将其改为独立的顶层组件即可避免这个问题。

解决方案

把渲染树形节点的逻辑提取为独立的顶层组件,通过props传递所需的节点数据和回调函数,确保组件实例在重渲染时被复用。

修改后的代码示例

1. 提取为顶层组件

// 独立的树形节点组件,接收必要的props
const TreeItemNode = ({ treeNode, handleCategoryInputChange, handleRemovecategory, handleAddSubCategory }) => {
  const hasChildren = treeNode.children?.length > 0;

  return (
    <>
      <CustomTreeItem
        className={`json-display ${treeNode.placeholder}`}
        key={treeNode.id}
        label={
          <div className="flex items-center gap-1 border border-[#e0dbdb] rounded-lg px-2 min-h-[36px] w-full my-[5px]">
            <input
              type="text"
              className="outline-none text-[12px] w-full"
              placeholder={treeNode.parentId ? "Sub-Category" : "Category"}
              value={treeNode.name || ""}
              onChange={(e) =>
                handleCategoryInputChange(treeNode.id, e.target.value)
              }
            />
            {!treeNode.firstCategory && (
              <Button
                icon={<FaTimes color="#adadad" size={14} />}
                onClick={() => handleRemovecategory(treeNode.id)}
                customClasses={`w-fit text-[10px] p-0 m-0 mx-0 mr-0 py-0 px-0  bg-transparent `}
              />
            )}
            {hasChildren && (
              <Button
                icon={<AiOutlinePlusSquare color="#bcbcbc" size={20} />}
                onClick={() => handleAddSubCategory(treeNode.id)}
                customClasses={`w-fit text-[10px] p-0 m-0 mx-0 mr-0 py-0 px-0  bg-transparent absolute translate-x-[12px]`}
              />
            )}
          </div>
        }
        nodeId={treeNode.id}
        defaultExpanded={[treeNode.id, treeNode.parentId]}
        onClick={() => console.log(treeNode)}
      >
        {hasChildren && treeNode.children.map(child => (
          <TreeItemNode
            key={child.id}
            treeNode={child}
            handleCategoryInputChange={handleCategoryInputChange}
            handleRemovecategory={handleRemovecategory}
            handleAddSubCategory={handleAddSubCategory}
          />
        ))}
      </CustomTreeItem>
      {/* 无子女节点时显示添加按钮 */}
      {!hasChildren && (
        <Button
          icon={<AiOutlinePlusSquare color="#bcbcbc" size={20} />}
          onClick={() => handleAddSubCategory(treeNode.id)}
          customClasses={`w-fit text-[10px] p-0 m-0 mx-0 mr-0 py-0 px-0  bg-transparent translate-y-[-23px] translate-x-[3px] absolute mr-[30px]`}
        />
      )}
    </>
  );
};

2. 在父组件中调用该组件

<TreeView
  aria-label="file system navigator"
  expanded={expanded}
  onNodeToggle={handleToggle}
  defaultCollapseIcon={<ExpandMoreIcon />}
  defaultExpandIcon={<ChevronRightIcon />}
  sx={{
    height: 240,
    flexGrow: 1,
    maxWidth: 400,
    overflowY: "auto",
  }}
>
  {categories?.map(category => (
    <TreeItemNode
      key={category.id}
      treeNode={category}
      handleCategoryInputChange={handleCategoryInputChange}
      handleRemovecategory={handleRemovecategory}
      handleAddSubCategory={handleAddSubCategory}
    />
  ))}
</TreeView>

关键说明

  • 提取后的TreeItemNode是顶层组件,不会随父组件重渲染而重新创建,React会复用已有组件实例,输入框焦点得以保留
  • 所有业务逻辑相关的回调函数和节点数据都通过props传递,保证组件内部能正常访问所需资源
  • 合并了原代码中重复的CustomTreeItem渲染逻辑,减少代码冗余,提升可维护性

内容的提问来源于stack exchange,提问作者Cool Dev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 03:55:27