Skip to content

Examples

Custom Style

Preview

Source

tsx
import { useHeTree, sortFlatData } from "he-tree-react"; import { useState } from 'react';  export default function BasePage() {  const keys = { idKey: 'id', parentIdKey: 'parent_id' };  const [data, setdata] = useState(() => sortFlatData([  {  id: 1,  parent_id: null,  name: "Root Category",  },  {  id: 2,  parent_id: 1,  name: "Technology",  },  {  id: 5,  parent_id: 2,  name: "Hardware",  },  {  id: 10,  parent_id: 5,  name: "Computer Components",  },  {  id: 4,  parent_id: 2,  name: "Programming",  },  {  id: 8,  parent_id: 4,  name: "Python",  },  {  id: 3,  parent_id: 1,  name: "Science",  },  {  id: 7,  parent_id: 3,  name: "Biology",  },  {  id: 6,  parent_id: 3,  name: "Physics",  },  ], keys));  const { renderTree, placeholder } = useHeTree({  ...keys,  data,  dataType: 'flat',  onChange: setdata,  renderNodeBox: ({ stat, attrs, isPlaceholder }) => (  <div {...attrs} key={attrs.key} className="my-node-box">  {isPlaceholder ? <div className="my-placeholder">DROP HERE</div>  : <div className="my-node">  <span className="drag-handler" draggable={stat.draggable}>{dragIcon()}</span>  {stat.node.name}  </div>  }  </div>  ),  })  return <>  <h3 style={{ margin: '0 0 0 110px', padding: '20px 0 0px' }}>Draggable Tree</h3>  <div>  {renderTree({ className: `my-tree ${placeholder ? 'dragging' : 'no-dragging'}` })}  </div>  <style>{`  .my-tree{  width: 300px;   border: 1px solid #ccc;   border-radius: 5px;  margin: 20px;   padding: 20px;  }  .my-placeholder{  height:40px;  border: 1px dashed blue;  border-radius: 3px;  background-color: #f3ffff;  display: flex;  align-items: center;  justify-content: center;  font-size: small;  }  /*.no-dragging .my-node-box:hover{  background-color: #eee;  }*/  .my-node-box:not(:last-child){  margin-bottom: 10px;  }  .my-node{  padding: 5px 10px;  padding-left: 30px;  border: 1px solid #e2e2e2;  border-radius: 3px;  background-color: #f0f0f0;  display: flex;  align-items: center;  position: relative;  box-shadow: 1px 1px 3px 0px rgb(0 0 0 / 19%);  }  .no-dragging .my-node:hover{  background-color: #ebfeff;  }  .drag-handler{  position: absolute;  left: 0;  top: 0;  width: 30px;  height: 100%;  display: flex;  align-items: center;  justify-content: center;  cursor: grab;  }  .drag-handler:hover{  background-color: #f0f0f0;  }  .my-node svg{  width:16px;  }  `}</style>  </> }  function dragIcon() {  return <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>drag-horizontal-variant</title><path d="M21 11H3V9H21V11M21 13H3V15H21V13Z" /></svg> }

Flat Data

Preview

Source

tsx
import { useHeTree, sortFlatData } from "he-tree-react"; import { useState } from 'react';  export default function BasePage() {  const keys = { idKey: 'id', parentIdKey: 'parent_id' };  const [data, setdata] = useState(() => sortFlatData([  {  id: 1,  parent_id: null,  name: "Root Category",  },  {  id: 2,  parent_id: 1,  name: "Technology",  },  {  id: 5,  parent_id: 2,  name: "Hardware",  },  {  id: 10,  parent_id: 5,  name: "Computer Components",  },  {  id: 4,  parent_id: 2,  name: "Programming",  },  {  id: 8,  parent_id: 4,  name: "Python",  },  {  id: 3,  parent_id: 1,  name: "Science",  },  {  id: 7,  parent_id: 3,  name: "Biology",  },  {  id: 6,  parent_id: 3,  name: "Physics",  },  ], keys));  const { renderTree } = useHeTree({  ...keys,  data,  dataType: 'flat',  onChange: setdata,  renderNode: ({ id, node, open, checked }) => <div>  {node.name}  </div>,  })  return <div>  {renderTree({ style: { width: '300px', border: '1px solid #555', padding: '20px' } })}  </div> }

Tree-shaped Data

Preview

Source

tsx
import { useHeTree } from "he-tree-react"; import { useState } from 'react';  export default function BasePage() {  const [data, setdata] = useState(() => [  {  id: 1,  name: "Root Category",  children: [  {  id: 2,  name: "Technology",  children: [  {  id: 5,  name: "Hardware",  children: [  {  id: 10,  name: "Computer Components",  children: [],  },  ],  },  {  id: 4,  name: "Programming",  children: [  {  id: 8,  name: "Python",  children: [],  },  ],  },  ],  },  {  id: 3,  name: "Science",  children: [  {  id: 7,  name: "Biology",  children: [],  },  {  id: 6,  name: "Physics",  children: [],  },  ],  },  ],  },  ]);  const { renderTree } = useHeTree({  data,  dataType: 'tree',  childrenKey: 'children',  onChange: setdata,  renderNode: ({ id, node, open, checked }) => <div>  {node.name}  </div>,  })  return <div>  {renderTree({ style: { width: '300px', border: '1px solid #555', padding: '20px' } })}  </div> }

Trigger Element

Preview

Source

tsx
import { useHeTree, sortFlatData } from "he-tree-react"; import { useState } from 'react';  export default function BasePage() {  const keys = { idKey: 'id', parentIdKey: 'parent_id' };  // prettier-ignore  const [data, setdata] = useState(() => sortFlatData([{ id: 1, parent_id: null, name: "Root Category", }, { id: 2, parent_id: 1, name: "Technology", }, { id: 5, parent_id: 2, name: "Hardware", }, { id: 10, parent_id: 5, name: "Computer Components", }, { id: 4, parent_id: 2, name: "Programming", }, { id: 8, parent_id: 4, name: "Python", }, { id: 3, parent_id: 1, name: "Science", }, { id: 7, parent_id: 3, name: "Biology", }, { id: 6, parent_id: 3, name: "Physics", },], keys));  const { renderTree } = useHeTree({  ...keys,  data,  dataType: 'flat',  onChange: setdata,  renderNode: ({ id, node, open, checked, draggable }) => <div>  <button draggable={draggable}>Drag</button>  {node.name}  </div>,  })  return <div>  {renderTree({ style: { width: '300px', border: '1px solid #555', padding: '20px' } })}  </div> }

Placeholder

Preview

Source

tsx
import { useHeTree, sortFlatData } from "he-tree-react"; import { useState } from 'react';  export default function BasePage() {  const keys = { idKey: 'id', parentIdKey: 'parent_id' };  // prettier-ignore  const [data, setdata] = useState(() => sortFlatData([{ id: 1, parent_id: null, name: "Root Category", }, { id: 2, parent_id: 1, name: "Technology", }, { id: 5, parent_id: 2, name: "Hardware", }, { id: 10, parent_id: 5, name: "Computer Components", }, { id: 4, parent_id: 2, name: "Programming", }, { id: 8, parent_id: 4, name: "Python", }, { id: 3, parent_id: 1, name: "Science", }, { id: 7, parent_id: 3, name: "Biology", }, { id: 6, parent_id: 3, name: "Physics", },], keys));  const { renderTree } = useHeTree({  ...keys,  data,  dataType: 'flat',  onChange: setdata,  renderNodeBox: ({ stat, attrs, isPlaceholder }) => (  <div {...attrs} key={attrs.key}>  {isPlaceholder ? <div className="my-drag-placeholder">drop here</div>  : <div className="mynode">{stat.node.name}</div>  }  </div>  ),  })  return <div>  {renderTree({ className: 'mytree', style: { width: '300px', border: '1px solid #555', padding: '20px' } })}  <style>{`  .mytree [data-node-box]{  padding: 5px 0;  }  .mytree [data-node-box]:hover{  background-color: #eee;  }  .mytree .he-tree-drag-placeholder{  height: 30px;  line-height: 30px;  text-align: center;  border: 1px dashed red;  }  .mynode{  padding-left:5px;  }  `}</style>  </div> }

Open

Preview

Source

tsx
import { useHeTree, sortFlatData, openParentsInFlatData } from "he-tree-react"; import type { Id } from "he-tree-react"; import { useState } from 'react';  export default function BasePage() {  const keys = { idKey: 'id', parentIdKey: 'parent_id' };  // prettier-ignore  const [data, setdata] = useState(() => sortFlatData([{ id: 1, parent_id: null, name: "Root Category", }, { id: 2, parent_id: 1, name: "Technology", }, { id: 5, parent_id: 2, name: "Hardware", }, { id: 10, parent_id: 5, name: "Computer Components", }, { id: 4, parent_id: 2, name: "Programming", }, { id: 8, parent_id: 4, name: "Python", }, { id: 3, parent_id: 1, name: "Science", }, { id: 7, parent_id: 3, name: "Biology", }, { id: 6, parent_id: 3, name: "Physics", },], keys));  const [openIds, setopenIds] = useState<Id[] | undefined>([]);  const handleOpen = (id: Id, open: boolean) => {  if (open) {  setopenIds([...(openIds || allIds), id]);  } else {  setopenIds((openIds || allIds).filter((i) => i !== id));  }  }  const { renderTree, allIds } = useHeTree({  ...keys,  data,  dataType: 'flat',  onChange: setdata,  openIds,  renderNode: ({ id, node, open, checked, draggable }) => <div>  <button onClick={() => handleOpen(id, !open)}>{open ? '-' : '+'}</button>  {node.name} - {id}  </div>,  })  return <div>  <button onClick={() => setopenIds(allIds)}>Open All</button>  <button onClick={() => setopenIds([])}>Close All</button>  <button onClick={() => setopenIds(openParentsInFlatData(data, openIds || allIds, 8, keys))}>Open 'Python'</button>  <button onClick={() => setopenIds(openParentsInFlatData(data, [], 8, keys))}>Only Open 'Python'</button>  {renderTree({ style: { width: '300px', border: '1px solid #555', padding: '20px' } })}  </div> }

Checked

Preview

Source

tsx
import { useHeTree, sortFlatData, updateCheckedInFlatData } from "he-tree-react"; import type { Id } from "he-tree-react"; import { useState } from 'react';  export default function BasePage() {  const keys = { idKey: 'id', parentIdKey: 'parent_id' };  // prettier-ignore  const [data, setdata] = useState(() => sortFlatData([{ id: 1, parent_id: null, name: "Root Category", }, { id: 2, parent_id: 1, name: "Technology", }, { id: 5, parent_id: 2, name: "Hardware", }, { id: 10, parent_id: 5, name: "Computer Components", }, { id: 4, parent_id: 2, name: "Programming", }, { id: 8, parent_id: 4, name: "Python", }, { id: 3, parent_id: 1, name: "Science", }, { id: 7, parent_id: 3, name: "Biology", }, { id: 6, parent_id: 3, name: "Physics", },], keys));  const [checkedIds, setcheckedIds] = useState<Id[]>([]);  const [semiCheckedIds, setsemiCheckedIds] = useState<Id[]>([]);  const handleChecked = (id: Id, checked: boolean) => {  const r = updateCheckedInFlatData(data, checkedIds, id, checked, keys);  setcheckedIds(r[0]);  setsemiCheckedIds(r[1]);  }  const { renderTree } = useHeTree({  ...keys,  data,  dataType: 'flat',  onChange: setdata,  checkedIds,  renderNode: ({ id, node, open, checked, draggable }) => <div>  <input type="checkbox" checked={checked || false} onChange={() => handleChecked(id, !checked)} />  {node.name} - {id}  </div>,  })  return <div>  Checked: {JSON.stringify(checkedIds)} <br />  Semi-Checked: {JSON.stringify(semiCheckedIds)}  {renderTree({ style: { width: '300px', border: '1px solid #555', padding: '20px' } })}  </div> }

Draggable & Droppable

Preview

Source

tsx
import { useHeTree, sortFlatData } from "he-tree-react"; import { useState } from 'react';  export default function BasePage() {  const keys = { idKey: 'id', parentIdKey: 'parent_id' };  // prettier-ignore  const [data, setdata] = useState(() => sortFlatData([{ id: 2, parent_id: 1, name: "Technology", }, { id: 5, parent_id: 2, name: "Hardware", }, { id: 10, parent_id: 5, name: "Computer Components", }, { id: 4, parent_id: 2, name: "Programming", }, { id: 8, parent_id: 4, name: "Python", }, { id: 3, parent_id: 1, name: "Science", }, { id: 7, parent_id: 3, name: "Biology", }, { id: 6, parent_id: 3, name: "Physics", },], keys));  const { renderTree } = useHeTree({  ...keys,  data,  dataType: 'flat',  onChange: setdata,  renderNode: ({ id, node, open, checked, draggable }) => <div>  {node.name} - {id}  </div>,  canDrag: ({ id }) => id === 2 ? true : (id === 3 ? false : undefined),  canDrop: ({ id }) => id === 3 ? true : (id === 2 ? false : undefined),  canDropToRoot: (index) => false,  })  return <div>  {renderTree({ style: { width: '300px', border: '1px solid #555', padding: '20px' } })}  </div> }

Open when drag onto

Preview

Source

tsx
import { useHeTree, sortFlatData } from "he-tree-react"; import type { Id } from "he-tree-react"; import { useState } from 'react';  export default function BasePage() {  const keys = { idKey: 'id', parentIdKey: 'parent_id' };  // prettier-ignore  const [data, setdata] = useState(() => sortFlatData([{ id: 1, parent_id: null, name: "Root Category", }, { id: 2, parent_id: 1, name: "Technology", }, { id: 5, parent_id: 2, name: "Hardware", }, { id: 10, parent_id: 5, name: "Computer Components", }, { id: 4, parent_id: 2, name: "Programming", }, { id: 8, parent_id: 4, name: "Python", }, { id: 3, parent_id: 1, name: "Science", }, { id: 7, parent_id: 3, name: "Biology", }, { id: 6, parent_id: 3, name: "Physics", },], keys));  const [openIds, setopenIds] = useState<Id[] | undefined>([1, 3]);  const handleOpen = (id: Id, open: boolean) => {  if (open) {  setopenIds([...(openIds || allIds), id]);  } else {  setopenIds((openIds || allIds).filter((i) => i !== id));  }  }  const { renderTree, allIds } = useHeTree({  ...keys,  data,  dataType: 'flat',  onChange: setdata,  openIds,  renderNode: ({ id, node, open, checked, draggable }) => <div>  <button onClick={() => handleOpen(id, !open)}>{open ? '-' : '+'}</button>  {node.name} - {id}  </div>,  dragOpen: true,  onDragOpen(stat) {  handleOpen(stat.id, true)  },  })  return <div>  {renderTree({ style: { width: '300px', border: '1px solid #555', padding: '20px' } })}  </div> }

Update Flat Data

Preview

Source

tsx
import {  useHeTree, sortFlatData,  addToFlatData, removeByIdInFlatData } from "he-tree-react"; import type { Id } from "he-tree-react"; import { useRef, useState } from 'react';  export default function BasePage() {  const keys = { idKey: 'id', parentIdKey: 'parent_id' };  // prettier-ignore  const [data, setdata] = useState(() => sortFlatData([{ id: 1, parent_id: null, name: "Root Category", }, { id: 2, parent_id: 1, name: "Technology", }, { id: 5, parent_id: 2, name: "Hardware", }, { id: 10, parent_id: 5, name: "Computer Components", }, { id: 4, parent_id: 2, name: "Programming", }, { id: 8, parent_id: 4, name: "Python", }, { id: 3, parent_id: 1, name: "Science", }, { id: 7, parent_id: 3, name: "Biology", }, { id: 6, parent_id: 3, name: "Physics", },], keys));  const add = (pid: Id) => {  let id = parseInt(Math.random().toString().substring(2, 5));  let newData = [...data];  addToFlatData(newData, { id, parent_id: pid as number, name: "New" }, 0, keys)  setdata(newData);  }  const remove = (id: Id) => {  let newData = [...data];  removeByIdInFlatData(newData, id as number, keys)  setdata(newData);  }  const initialData = useRef<typeof data>();  initialData.current = initialData.current || data;  const { renderTree } = useHeTree({  ...keys,  data,  dataType: 'flat',  onChange: setdata,  renderNode: ({ id, node, draggable }) => <div>  <button draggable={draggable}>👉</button>  {node.name} - {id} -  <button onClick={() => add(id)}>+</button>  <button onClick={() => remove(id)}>-</button>  </div>,  })  return <div>  <button onClick={() => setdata(initialData.current!)}>Restore</button>  {renderTree({ style: { width: '300px', border: '1px solid #555', padding: '20px' } })}  </div> }

Update Flat Data with immer

Preview

Source

tsx
import {  useHeTree, sortFlatData,  addToFlatData, removeByIdInFlatData } from "he-tree-react"; import type { Id } from "he-tree-react"; import { useRef } from 'react'; import { useImmer } from "use-immer";  export default function BasePage() {  const keys = { idKey: 'id', parentIdKey: 'parent_id' };  // prettier-ignore  const [data, setdata] = useImmer(() => sortFlatData([{ id: 1, parent_id: null, name: "Root Category", }, { id: 2, parent_id: 1, name: "Technology", }, { id: 5, parent_id: 2, name: "Hardware", }, { id: 10, parent_id: 5, name: "Computer Components", }, { id: 4, parent_id: 2, name: "Programming", }, { id: 8, parent_id: 4, name: "Python", }, { id: 3, parent_id: 1, name: "Science", }, { id: 7, parent_id: 3, name: "Biology", }, { id: 6, parent_id: 3, name: "Physics", },], keys));  const add = (pid: Id) => {  let id = parseInt(Math.random().toString().substring(2, 5));  setdata(draft => {  addToFlatData(draft, { id, parent_id: pid as number, name: "New" }, 0, keys)  });  }  const remove = (id: Id) => {  setdata(draft => {  removeByIdInFlatData(draft, id as number, keys)  })  }  const edit = (id: Id) => {  let newName = prompt("Enter new name")  setdata(draft => {  if (newName) {  draft.find(node => node.id === id)!.name = newName  }  })  }  const initialData = useRef<typeof data>();  initialData.current = initialData.current || data;  const { renderTree } = useHeTree({  ...keys,  data,  dataType: 'flat',  onChange: setdata,  renderNode: ({ id, node, draggable }) => <div>  <button draggable={draggable}>👉</button>  {node.name} - {id} -  <button onClick={() => add(id)}>+</button>  <button onClick={() => remove(id)}>-</button>  <button onClick={() => edit(id)}>Edit</button>  </div>,  })  return <div>  <button onClick={() => setdata(initialData.current!)}>Restore</button>  {renderTree({ style: { width: '300px', border: '1px solid #555', padding: '20px' } })}  </div> }

Update Tree Data with immer

Preview

Source

tsx
import { useHeTree, findTreeData } from "he-tree-react"; import type { Id } from "he-tree-react"; import { useRef } from 'react'; import { useImmer } from "use-immer";  export default function BasePage() {  const CHILDREN = 'children'  const keys = { idKey: 'id', childrenKey: CHILDREN };  // prettier-ignore  const [data, setdata] = useImmer(() => [{ id: 1, name: "Root Category", children: [{ id: 2, name: "Technology", children: [{ id: 5, name: "Hardware", children: [{ id: 10, name: "Computer Components", children: [], },], }, { id: 4, name: "Programming", children: [{ id: 8, name: "Python", children: [], },], },], }, { id: 3, name: "Science", children: [{ id: 7, name: "Biology", children: [], }, { id: 6, name: "Physics", children: [], },], },], },]);  const add = (pid: Id) => {  let id = parseInt(Math.random().toString().substring(2, 5));  setdata(draft => {  findTreeData(draft, (node) => node.id === pid, CHILDREN)![CHILDREN].unshift({ id, name: "New", [CHILDREN]: [], })  })  }  const remove = (id: Id, pid: Id | null) => {  setdata(draft => {  const children = findTreeData(draft, (node,) => node.id === pid, CHILDREN)![CHILDREN]  children.splice(children.findIndex(t => t.id === id), 1)  })  }  const edit = (id: Id) => {  let newName = prompt("Enter new name")  setdata(draft => {  if (newName) {  findTreeData(draft, (node) => node.id === id, CHILDREN)!.name = newName  }  })  }  const initialData = useRef<typeof data>();  initialData.current = initialData.current || data;  const { renderTree } = useHeTree({  ...keys,  data,  dataType: 'tree',  onChange: setdata,  renderNode: ({ id, pid, node, draggable }) => <div>  <button draggable={draggable}>👉</button>  {node.name} - {id} -  <button onClick={() => add(id)}>+</button>  <button onClick={() => remove(id, pid)}>-</button>  <button onClick={() => edit(id)}>Edit</button>  </div>,  })  return <div>  <button onClick={() => setdata(initialData.current!)}>Restore</button>  {renderTree({ style: { width: '300px', border: '1px solid #555', padding: '20px' } })}  </div> }

Drag from External

Preview

Source

tsx
import { useHeTree, sortFlatData, addToFlatData } from "he-tree-react"; import { useImmer } from "use-immer";  export default function BasePage() {  const keys = { idKey: 'id', parentIdKey: 'parent_id' };  // prettier-ignore  const [data, setdata] = useImmer(() => sortFlatData([{ id: 1, parent_id: null, name: "Root Category", }, { id: 2, parent_id: 1, name: "Technology", }, { id: 5, parent_id: 2, name: "Hardware", }, { id: 10, parent_id: 5, name: "Computer Components", }, { id: 4, parent_id: 2, name: "Programming", }, { id: 8, parent_id: 4, name: "Python", }, { id: 3, parent_id: 1, name: "Science", }, { id: 7, parent_id: 3, name: "Biology", }, { id: 6, parent_id: 3, name: "Physics", },], keys));  const { renderTree, allIds } = useHeTree({  ...keys,  data,  dataType: 'flat',  onChange: setdata,  renderNode: ({ id, node, open, checked, draggable }) => <div>  {node.name} - {id}  </div>,  onExternalDragOver: (e) => true,  onExternalDrop: (e, parentStat, index) => {  setdata(draft => {  const newNode = { id: 100 + data.length, parent_id: parentStat?.id ?? null, name: "New Node" }  addToFlatData(draft, newNode, index, keys)  })  },  })  return <div>  <button draggable={true}>Drag me in to the tree</button>  {renderTree({ style: { width: '300px', border: '1px solid #555', padding: '20px' } })}  </div> }

Big Data

Preview

Source

tsx
import { useHeTree, sortFlatData } from "he-tree-react"; import type { Id } from "he-tree-react"; import { useState } from 'react';  export default function BasePage() {  const keys = { idKey: 'id', parentIdKey: 'pid' };  // prettier-ignore  const [data, setdata] = useState(() => sortFlatData(createData(), keys));  const [openIds, setopenIds] = useState<Id[] | undefined>([]);  const handleOpen = (id: Id, open: boolean) => {  if (open) {  setopenIds([...(openIds || allIds), id]);  } else {  setopenIds((openIds || allIds).filter((i) => i !== id));  }  }  const { renderTree, allIds } = useHeTree({  ...keys,  data,  dataType: 'flat',  onChange: setdata,  openIds,  virtual: true,  renderNode: ({ id, node, open, checked, draggable }) => <div>  <button onClick={() => handleOpen(id, !open)}>{open ? '-' : '+'}</button>  {id}  </div>,  })  return <div>  {renderTree({ style: { width: '300px', height: '300px', border: '1px solid #555', padding: '20px' } })}  </div> }  // generate 10000 nodes function createData() {  const genId = () => result.length  const result: { id: number, pid: number | null }[] = [];  for (let i = 0; i < 1000; i++) {  let id1 = genId()  result.push({ id: id1, pid: null })  for (let j = 0; j < 4; j++) {  result.push({ id: genId(), pid: id1 })  }  let id2 = genId()  result.push({ id: id2, pid: null })  for (let j = 0; j < 4; j++) {  result.push({ id: genId(), pid: id2 })  }  }  return result; }

Scroll to Node

Preview

Source

tsx
import { useHeTree, sortFlatData } from "he-tree-react"; import type { Id } from "he-tree-react"; import { useState } from 'react';  export default function BasePage() {  const keys = { idKey: 'id', parentIdKey: 'pid' };  // prettier-ignore  const [data, setdata] = useState(() => sortFlatData(createData(), keys));  const [openIds, setopenIds] = useState<Id[] | undefined>([]);  const handleOpen = (id: Id, open: boolean) => {  if (open) {  setopenIds([...(openIds || allIds), id]);  } else {  setopenIds((openIds || allIds).filter((i) => i !== id));  }  }  const { renderTree, allIds, scrollToNode } = useHeTree({  ...keys,  data,  dataType: 'flat',  onChange: setdata,  openIds,  virtual: true,  renderNode: ({ id, node, open, checked, draggable }) => <div>  <button onClick={() => handleOpen(id, !open)}>{open ? '-' : '+'}</button>  {id}  </div>,  })  return <div>  <button onClick={() => scrollToNode(910)}>Scroll to 910</button>  {renderTree({ style: { width: '300px', height: '300px', border: '1px solid #555', padding: '20px' } })}  </div> }  // generate 10000 nodes function createData() {  const genId = () => result.length  const result: { id: number, pid: number | null }[] = [];  for (let i = 0; i < 1000; i++) {  let id1 = genId()  result.push({ id: id1, pid: null })  for (let j = 0; j < 4; j++) {  result.push({ id: genId(), pid: id1 })  }  let id2 = genId()  result.push({ id: id2, pid: null })  for (let j = 0; j < 4; j++) {  result.push({ id: genId(), pid: id2 })  }  }  return result; }