Repository: element-plus/element-plus
File: packages/components/tree-v2/src/composables/useTree.ts (TypeScript)

Code before:
      currentKey.value = node.key
      emit(CURRENT_CHANGE, node.data, node)
    }
  }

  function handleNodeCheck(node: TreeNode, checked: CheckboxValueType) {
    toggleCheckbox(node, checked)
  }

  function expandNode(node: TreeNode) {
    const keySet = expandedKeySet.value
    if (tree.value && props.accordion) {
      // whether only one node among the same level can be expanded at one time
      const { treeNodeMap } = tree.value
      keySet.forEach((key) => {
        const treeNode = treeNodeMap.get(key)
        if (node && node.level === treeNode?.level) {
          keySet.delete(key)
          treeNode.expanded = false
        }
      })
    }
    keySet.add(node.key)
    const _node = getNode(node.key)
    _node && (_node.expanded = true)
    emit(NODE_EXPAND, node.data, node)
  }

  function collapseNode(node: TreeNode) {
    expandedKeySet.value.delete(node.key)
    const _node = getNode(node.key)
    _node && (_node.expanded = false)
    emit(NODE_COLLAPSE, node.data, node)
  }

  function isDisabled(node: TreeNode): boolean {
    return !!node.disabled
  }

  function isCurrent(node: TreeNode): boolean {
    const current = currentKey.value
    return current !== undefined && current === node.key
  }

  function getCurrentNode(): TreeNodeData | undefined {
    if (!currentKey.value) return undefined
    return tree.value?.treeNodeMap.get(currentKey.value)?.data
  }

  function getCurrentKey(): TreeKey | undefined {
    return currentKey.value

Review comment (suggestion):
This fixes the issue with the expanded state, but I wonder whether we should respect the user's changes if the developer modifies node or data when this function is triggered?

[example](https://element-plus.run/#eyJBcHAudnVlIjoiPHRlbXBsYXRlPlxuICA8ZWwtYnV0dG9uIEBjbGljaz1cImNvbGxhcHNlQWxsTm9kZVwiPuaUtui1t+aJgOaciTwvZWwtYnV0dG9uPlxuICA8ZWwtdHJlZS12MlxuICAgIDpkYXRhPVwidHJlZURhdGFcIlxuICAgIGhpZ2hsaWdodC1jdXJyZW50XG4gICAgOmV4cGFuZC1vbi1jbGljay1ub2RlPVwiZmFsc2VcIlxuICAgIHJlZj1cInJlZlRyZWVcIlxuICAgIEBub2RlLWV4cGFuZD1cInRvZ2dsZUV4cGFuZGVkXCJcbiAgICBAbm9kZS1jb2xsYXBzZT1cInRvZ2dsZUV4cGFuZGVkXCJcbiAgPlxuICAgIDx0ZW1wbGF0ZSAjZGVmYXVsdD1cInsgbm9kZSB9XCI+XG4gICAgICA8ZGl2IEBkYmxjbGljaz1cInRvZ2dsZUV4cGFuZChub2RlKVwiPnt7IG5vZGUubGFiZWwgfX08L2Rpdj5cbiAgICA8L3RlbXBsYXRlPlxuICA8L2VsLXRyZWUtdjI+XG48L3RlbXBsYXRlPlxuXG48c2NyaXB0IHNldHVwPlxuaW1wb3J0IHsgcmVhY3RpdmUsIHJlZiB9IGZyb20gJ3Z1ZSdcblxuY29uc3QgdHJlZURhdGEgPSByZWFjdGl2ZShbXG4gIHtcbiAgICBpZDogJzEnLFxuICAgIGxhYmVsOiAnTGV2ZWwgb25lIDEnLFxuICAgIGNoaWxkcmVuOiBbXG4gICAgICB7XG4gICAgICAgIGlkOiAnMS0xJyxcbiAgICAgICAgbGFiZWw6ICdMZXZlbCB0d28gMS0xJyxcbiAgICAgIH0sXG4gICAgXSxcbiAgfSxcbl0pXG5cbmNvbnN0IHRvZ2dsZUV4cGFuZGVkID0gKGRhdGEsIG5vZGUpID0+IHtcbiAgY29uc29sZS5sb2coZGF0YSwgbm9kZSlcbn1cblxuY29uc3QgcmVmVHJlZSA9IHJlZigpXG5mdW5jdGlvbiB0b2dnbGVFeHBhbmQobm9kZSkge1xuICBpZiAobm9kZS5leHBhbmRlZCkge1xuICAgIHJlZlRyZWUudmFsdWUuY29sbGFwc2VOb2RlKG5vZGUpXG4gIH0gZWxzZSB7XG4gICAgcmVmVHJlZS52YWx1ZS5leHBhbmROb2RlKHsuLi5ub2RlLCBkYXRhOiB7Li4ubm9kZS5kYXRhLCBhOiAndGVzdCd9fSlcbiAgfVxufVxuXG5mdW5jdGlvbiBjb2xsYXBzZUFsbE5vZGUoKSB7XG4gIGNvbnN0IHJvb3ROb2RlID0gcmVmVHJlZS52YWx1ZS5nZXROb2RlKCcxJylcbiAgY29sbGFwc2VBbGwoW3Jvb3ROb2RlXSlcbn1cblxuLy8g6YCS5b2S5pS26LW35omA5pyJ5bGV5byA55qE6IqC54K5XG5mdW5jdGlvbiBjb2xsYXBzZUFsbChub2Rlcykge1xuICBub2Rlcy5mb3JFYWNoKChub2RlKSA9PiB7XG4gICAgaWYgKG5vZGUuZXhwYW5kZWQpIHtcbiAgICAgIHJlZlRyZWUudmFsdWUuY29sbGFwc2VOb2RlKG5vZGUpXG4gICAgfVxuICAgIC8vIOmAkuW9kuWkhOeQhuWtkOiKgueCuVxuICAgIGlmIChub2RlLmNoaWxkcmVuPy5sZW5ndGggPiAwKSB7XG4gICAgICBjb2xsYXBzZUFsbChub2RlLmNoaWxkcmVuKVxuICAgIH1cbiAgfSlcbn1cbjwvc2NyaXB0PlxuXG48c3R5bGUgc2NvcGVkIGxhbmc9XCJzY3NzXCI+PC9zdHlsZT5cbiIsImVsZW1lbnQtcGx1cy5qcyI6ImltcG9ydCBFbGVtZW50UGx1cyBmcm9tICdlbGVtZW50LXBsdXMnXG5pbXBvcnQgeyBnZXRDdXJyZW50SW5zdGFuY2UgfSBmcm9tICd2dWUnXG5cbmxldCBpbnN0YWxsZWQgPSBmYWxzZVxuYXdhaXQgbG9hZFN0eWxlKClcblxuZXhwb3J0IGZ1bmN0aW9uIHNldHVwRWxlbWVudFBsdXMoKSB7XG4gIGlmIChpbnN0YWxsZWQpIHJldHVyblxuICBjb25zdCBpbnN0YW5jZSA9IGdldEN1cnJlbnRJbnN0YW5jZSgpXG4gIGluc3RhbmNlLmFwcENvbnRleHQuYXBwLnVzZShFbGVtZW50UGx1cylcbiAgaW5zdGFsbGVkID0gdHJ1ZVxufVxuXG5leHBvcnQgZnVuY3Rpb24gbG9hZFN0eWxlKCkge1xuICBjb25zdCBzdHlsZXMgPSBbJ2h0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vZWxlbWVudC1wbHVzQDIuMTAuMy9kaXN0L2luZGV4LmNzcycsICdodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2VsZW1lbnQtcGx1c0AyLjEwLjMvdGhlbWUtY2hhbGsvZGFyay9jc3MtdmFycy5jc3MnXS5tYXAoKHN0eWxlKSA9PiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIGNvbnN0IGxpbmsgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdsaW5rJylcbiAgICAgIGxpbmsucmVsID0gJ3N0eWxlc2hlZXQnXG4gICAgICBsaW5rLmhyZWYgPSBzdHlsZVxuICAgICAgbGluay5hZGRFdmVudExpc3RlbmVyKCdsb2FkJywgcmVzb2x2ZSlcbiAgICAgIGxpbmsuYWRkRXZlbnRMaXN0ZW5lcignZXJyb3InLCByZWplY3QpXG4gICAgICBkb2N1bWVudC5ib2R5LmFwcGVuZChsaW5rKVxuICAgIH0pXG4gIH0pXG4gIHJldHVybiBQcm9taXNlLmFsbFNldHRsZWQoc3R5bGVzKVxufSIsInRzY29uZmlnLmpzb24iOiJ7XG4gIFwiY29tcGlsZXJPcHRpb25zXCI6IHtcbiAgICBcInRhcmdldFwiOiBcIkVTTmV4dFwiLFxuICAgIFwianN4XCI6IFwicHJlc2VydmVcIixcbiAgICBcIm1vZHVsZVwiOiBcIkVTTmV4dFwiLFxuICAgIFwibW9kdWxlUmVzb2x1dGlvblwiOiBcIkJ1bmRsZXJcIixcbiAgICBcInR5cGVzXCI6IFtcImVsZW1lbnQtcGx1cy9nbG9iYWwuZC50c1wiXSxcbiAgICBcImFsbG93SW1wb3J0aW5nVHNFeHRlbnNpb25zXCI6IHRydWUsXG4gICAgXCJhbGxvd0pzXCI6IHRydWUsXG4gICAgXCJjaGVja0pzXCI6IHRydWVcbiAgfSxcbiAgXCJ2dWVDb21waWxlck9wdGlvbnNcIjoge1xuICAgIFwidGFyZ2V0XCI6IDMuM1xuICB9XG59XG4iLCJQbGF5Z3JvdW5kTWFpbi52dWUiOiI8c2NyaXB0IHNldHVwPlxuaW1wb3J0IEFwcCBmcm9tICcuL0FwcC52dWUnXG5pbXBvcnQgeyBzZXR1cEVsZW1lbnRQbHVzIH0gZnJvbSAnLi9lbGVtZW50LXBsdXMuanMnXG5zZXR1cEVsZW1lbnRQbHVzKClcbjwvc2NyaXB0PlxuXG48dGVtcGxhdGU+XG4gIDxBcHAgLz5cbjwvdGVtcGxhdGU+XG4iLCJpbXBvcnQtbWFwLmpzb24iOiJ7XG4gIFwiaW1wb3J0c1wiOiB7XG4gICAgXCJ2dWVcIjogXCJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL0B2dWUvcnVudGltZS1kb21AbGF0ZXN0L2Rpc3QvcnVudGltZS1kb20uZXNtLWJyb3dzZXIuanNcIixcbiAgICBcIkB2dWUvc2hhcmVkXCI6IFwiaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9AdnVlL3NoYXJlZEBsYXRlc3QvZGlzdC9zaGFyZWQuZXNtLWJ1bmRsZXIuanNcIixcbiAgICBcImVsZW1lbnQtcGx1c1wiOiBcImh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vZWxlbWVudC1wbHVzQDIuMTAuMy9kaXN0L2luZGV4LmZ1bGwubWluLm1qc1wiLFxuICAgIFwiZWxlbWVudC1wbHVzL1wiOiBcImh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vZWxlbWVudC1wbHVzQDIuMTAuMy9cIixcbiAgICBcIkBlbGVtZW50LXBsdXMvaWNvbnMtdnVlXCI6IFwiaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9AZWxlbWVudC1wbHVzL2ljb25zLXZ1ZUAyL2Rpc3QvaW5kZXgubWluLmpzXCJcbiAgfSxcbiAgXCJzY29wZXNcIjoge31cbn0iLCJfbyI6eyJlcFZlcnNpb24iOiIyLjEwLjMifX0=)

At the very least, the latest expanded state needs to be emitted.

Code after:
      currentKey.value = node.key
      emit(CURRENT_CHANGE, node.data, node)
    }
  }

  function handleNodeCheck(node: TreeNode, checked: CheckboxValueType) {
    toggleCheckbox(node, checked)
  }

  function expandNode(node: TreeNode) {
    const keySet = expandedKeySet.value
    if (tree.value && props.accordion) {
      // whether only one node among the same level can be expanded at one time
      const { treeNodeMap } = tree.value
      keySet.forEach((key) => {
        const treeNode = treeNodeMap.get(key)
        if (node && node.level === treeNode?.level) {
          keySet.delete(key)
          treeNode.expanded = false
        }
      })
    }
    keySet.add(node.key)
    const _node = getNode(node.key)
    if (_node) {
      _node.expanded = true
      emit(NODE_EXPAND, _node.data, _node)
    }
  }

  function collapseNode(node: TreeNode) {
    expandedKeySet.value.delete(node.key)
    const _node = getNode(node.key)
    if (_node) {
      _node.expanded = false
      emit(NODE_COLLAPSE, _node.data, _node)
    }
  }

  function isDisabled(node: TreeNode): boolean {
    return !!node.disabled
  }

  function isCurrent(node: TreeNode): boolean {
    const current = currentKey.value
    return current !== undefined && current === node.key
  }

  function getCurrentNode(): TreeNodeData | undefined {
    if (!currentKey.value) return undefined
    return tree.value?.treeNodeMap.get(currentKey.value)?.data