Skip to content

Commit ff87f39

Browse files
committed
add keys
1 parent a81d69e commit ff87f39

2 files changed

Lines changed: 41 additions & 7 deletions

File tree

client/packages/lowcoder/src/comps/comps/navComp/components/MenuItemList.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ const NavTreeItemComponent = React.forwardRef<
5454
const { item, depth, collapsed, ...rest } = props;
5555
const { comp, path } = item;
5656

57-
console.log("NavTreeItemComponent", "collapsed", collapsed);
5857
const handlers = useContext(MenuItemHandlersContext);
5958

6059
const hasChildren = item.children && item.children.length > 0;
@@ -114,7 +113,9 @@ function convertToTreeItems(
114113
): TreeItems<NavTreeItemData> {
115114
return items.map((item, index) => {
116115
const path = [...basePath, index];
117-
const id = path.join("_");
116+
// Use stable itemKey if available, fallback to path-based ID for backwards compatibility
117+
const itemKey = item.getItemKey?.() || "";
118+
const id = itemKey || path.join("_");
118119
const subItems = item.getView().items || [];
119120

120121
return {

client/packages/lowcoder/src/comps/comps/navComp/navItemComp.tsx

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { BoolCodeControl, StringControl } from "comps/controls/codeControl";
22
import { clickEvent, eventHandlerControl } from "comps/controls/eventHandlerControl";
3+
import { valueComp } from "comps/generators";
34
import { list } from "comps/generators/list";
45
import { parseChildrenFromValueAndChildrenMap, ToViewReturn } from "comps/generators/multi";
5-
import { withDefault } from "comps/generators/simpleGenerators";
6+
import { migrateOldData, withDefault } from "comps/generators/simpleGenerators";
67
import { disabledPropertyView, hiddenPropertyView } from "comps/utils/propertyUtils";
8+
import { genRandomKey } from "comps/utils/idGenerator";
79
import { trans } from "i18n";
810
import _ from "lodash";
911
import { fromRecord, MultiBaseComp, Node, RecordNode, RecordNodeToValue } from "lowcoder-core";
@@ -18,6 +20,7 @@ const childrenMap = {
1820
hidden: BoolCodeControl,
1921
disabled: BoolCodeControl,
2022
active: BoolCodeControl,
23+
itemKey: valueComp<string>(""),
2124
onEvent: withDefault(eventHandlerControl(events), [
2225
{
2326
// name: "click",
@@ -35,6 +38,7 @@ type ChildrenType = {
3538
hidden: InstanceType<typeof BoolCodeControl>;
3639
disabled: InstanceType<typeof BoolCodeControl>;
3740
active: InstanceType<typeof BoolCodeControl>;
41+
itemKey: InstanceType<ReturnType<typeof valueComp<string>>>;
3842
onEvent: InstanceType<ReturnType<typeof eventHandlerControl>>;
3943
items: InstanceType<ReturnType<typeof navListComp>>;
4044
};
@@ -72,6 +76,10 @@ export class NavItemComp extends MultiBaseComp<ChildrenType> {
7276
this.children.items.addItem(value);
7377
}
7478

79+
getItemKey(): string {
80+
return this.children.itemKey.getView();
81+
}
82+
7583
exposingNode(): RecordNode<NavItemExposing> {
7684
return fromRecord({
7785
label: this.children.label.exposingNode(),
@@ -93,17 +101,42 @@ type NavItemExposing = {
93101
items: Node<RecordNodeToValue<NavItemExposing>[]>;
94102
};
95103

104+
// Migrate old nav items to ensure they have a stable itemKey
105+
function migrateNavItemData(oldData: any): any {
106+
if (!oldData) return oldData;
107+
108+
const migrated = {
109+
...oldData,
110+
itemKey: oldData.itemKey || genRandomKey(),
111+
};
112+
113+
// Also migrate nested items recursively
114+
if (Array.isArray(oldData.items)) {
115+
migrated.items = oldData.items.map((item: any) => migrateNavItemData(item));
116+
}
117+
118+
return migrated;
119+
}
120+
121+
const NavItemCompMigrate = migrateOldData(NavItemComp, migrateNavItemData);
122+
96123
export function navListComp() {
97-
const NavItemListCompBase = list(NavItemComp);
124+
const NavItemListCompBase = list(NavItemCompMigrate);
98125

99126
return class NavItemListComp extends NavItemListCompBase {
100127
addItem(value?: any) {
101128
const data = this.getView();
102129
this.dispatch(
103130
this.pushAction(
104-
value || {
105-
label: trans("menuItem") + " " + (data.length + 1),
106-
}
131+
value
132+
? {
133+
...value,
134+
itemKey: value.itemKey || genRandomKey(),
135+
}
136+
: {
137+
label: trans("menuItem") + " " + (data.length + 1),
138+
itemKey: genRandomKey(),
139+
}
107140
)
108141
);
109142
}

0 commit comments

Comments
 (0)