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

Next.js中Balkan FamilyTree自定义EditUI报错:this.editUI.init不是函数

解决Balkan FamilyTree自定义EditUI时init is not a function错误

核心问题分析

你遇到的错误本质是自定义的EditUI没有正确实现库要求的接口:要么init方法不存在,要么方法的this绑定丢失导致库调用时无法识别。另外Next.js的SSR环境也可能导致初始化时机不对,触发DOM相关错误。

解决方案1:TypeScript类实现(正确绑定this)

用箭头函数定义类方法,确保this始终指向类实例,避免绑定丢失:

class CustomEditForm {
  // 必须实现init方法,参数对应tree实例、节点数据、保存回调
  init = (tree: any, nodeData: any, onSave: (updatedData: any) => void) => {
    // 自定义弹窗/表单逻辑,示例用原生DOM创建
    const editModal = document.createElement('div');
    editModal.style.cssText = `position:fixed; top:50%; left:50%; transform:translate(-50%,-50%); padding:2rem; background:#fff; border-radius:8px; box-shadow:0 2px 10px rgba(0,0,0,0.1); z-index:9999;`;
    
    editModal.innerHTML = `
      <h3>编辑节点信息</h3>
      <div style="margin:1rem 0;">
        <label>姓名:</label>
        <input type="text" value="${nodeData.name}" style="padding:0.5rem; width:200px;" id="edit-name" />
      </div>
      <button style="padding:0.5rem 1rem; margin-right:1rem;" id="save-edit">保存</button>
      <button style="padding:0.5rem 1rem;" id="cancel-edit">取消</button>
    `;

    document.body.appendChild(editModal);

    // 保存逻辑
    document.getElementById('save-edit')?.addEventListener('click', () => {
      const updatedName = (document.getElementById('edit-name') as HTMLInputElement).value;
      // 调用库的回调更新节点
      onSave({ ...nodeData, name: updatedName });
      editModal.remove();
    });

    // 取消逻辑
    document.getElementById('cancel-edit')?.addEventListener('click', () => {
      editModal.remove();
    });
  };

  // 可选:实现destroy方法用于清理资源
  destroy = () => {
    const modal = document.querySelector('div[style*="z-index:9999"]');
    modal?.remove();
  };
}

解决方案2:函数式实现(返回包含init的对象)

如果用函数式写法,必须返回一个包含init方法的对象,而不是直接返回函数:

function createCustomEditUI() {
  return {
    init(tree, nodeData, onSave) {
      // 这里写和上面类实现一样的UI逻辑
    },
    destroy() {
      // 清理逻辑
    }
  };
}

Next.js中正确初始化EditUI

因为Balkan FamilyTree依赖DOM,必须在客户端组件中初始化EditUI,避免SSR阶段执行:

'use client'; // 标记为客户端组件

import { useEffect, useRef } from 'react';
import FamilyTree from '@balkanjs/react-family-tree';

export default function FamilyTreePage() {
  const treeRef = useRef<any>(null);
  // 你的节点数据
  const treeNodes = [/* 节点数组 */];

  useEffect(() => {
    if (treeRef.current) {
      // 获取树实例
      const treeInstance = treeRef.current.tree;
      // 绑定自定义EditUI
      treeInstance.editUI = new CustomEditForm();
      // 如果用函数式就写:treeInstance.editUI = createCustomEditUI();
    }
  }, []);

  return (
    <div style={{ width: '100%', height: '800px' }}>
      <FamilyTree
        ref={treeRef}
        nodes={treeNodes}
        // 其他配置项(比如theme、layout等)
      />
    </div>
  );
}

关键注意点

  1. 方法绑定:TS类中必须用箭头函数定义init/destroy,否则库调用时this会指向undefined,导致找不到方法。
  2. 客户端初始化:Next.js SSR阶段没有DOM,必须在useEffect或客户端组件中初始化EditUI,不能直接在组件顶层实例化。
  3. 接口匹配:自定义EditUI必须包含init方法,参数要和库要求的一致(tree实例、节点数据、保存回调)。

内容的提问来源于stack exchange,提问作者Anuj TBE

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 18:13:26