Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf1fbb60

Browse files
optimise lowcoder-design components
1 parent2524bf4 commitf1fbb60

File tree

7 files changed

+232
-135
lines changed

7 files changed

+232
-135
lines changed

‎client/packages/lowcoder-design/src/components/Modal/handler.tsx‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
importstyled,{css}from"styled-components";
2+
import{memo,useMemo}from"react";
23

34
typeResizeHandleAxis="s"|"w"|"e"|"n"|"sw"|"nw"|"se"|"ne";
45
typeReactRef<TextendsHTMLElement>={
@@ -83,8 +84,11 @@ const ResizeHandle = styled.div<{ $axis: string }>`
8384
${(props)=>(["sw","nw","se","ne"].indexOf(props.$axis)>=0 ?CornerHandle :"")};
8485
`;
8586

86-
constHandle=(axis:ResizeHandleAxis,ref:ReactRef<HTMLDivElement>)=>{
87-
return<ResizeHandleref={ref}$axis={axis}className={`react-resizable-handle`}></ResizeHandle>;
88-
};
87+
// Memoize Handle component
88+
constHandle=memo((axis:ResizeHandleAxis,ref:ReactRef<HTMLDivElement>)=>{
89+
return<ResizeHandleref={ref}$axis={axis}className="react-resizable-handle"/>;
90+
});
91+
92+
Handle.displayName='Handle';
8993

9094
exportdefaultHandle;

‎client/packages/lowcoder-design/src/components/Modal/index.tsx‎

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import{defaultasAntdModal,ModalPropsasAntdModalProps}from"antd/es/modal";
2-
import{useEffect,useState}from"react";
2+
import{useCallback,useEffect,useMemo,useState}from"react";
33
import{Resizable,ResizeHandle}from"react-resizable";
44
import{useResizeDetector}from"react-resize-detector";
55
importHandlefrom"./handler";
@@ -39,45 +39,60 @@ export function Modal(props: ModalProps) {
3939

4040
const[width,setWidth]=useState<number>();
4141
const[height,setHeight]=useState<number>();
42+
43+
// Memoize style object
44+
constmodalStyles=useMemo(()=>({
45+
body:{
46+
height:height??modalHeight,
47+
...styles?.body,
48+
}
49+
}),[height,modalHeight,styles?.body]);
50+
51+
// Memoize event handlers
52+
consthandleResizeStart=useCallback((event:React.SyntheticEvent,{ node, size, handle}:{node:HTMLElement;size:{width:number;height:number};handle:ResizeHandle})=>{
53+
props.onResizeStart?.(event,node,size,handle);
54+
},[props.onResizeStart]);
55+
56+
consthandleResize=useCallback((event:React.SyntheticEvent,{ node, size, handle}:{node:HTMLElement;size:{width:number;height:number};handle:ResizeHandle})=>{
57+
setWidth(size.width);
58+
setHeight(size.height);
59+
props.onResize?.(event,node,size,handle);
60+
},[props.onResize]);
61+
62+
consthandleResizeStop=useCallback((event:React.SyntheticEvent,{ node, size, handle}:{node:HTMLElement;size:{width:number;height:number};handle:ResizeHandle})=>{
63+
props.onResizeStop?.(event,node,size,handle);
64+
},[props.onResizeStop]);
65+
4266
useEffect(()=>{
4367
setWidth(undefined);
4468
// eslint-disable-next-line react-hooks/exhaustive-deps
4569
},[modalWidth]);
70+
4671
useEffect(()=>{
4772
setHeight(undefined);
4873
// eslint-disable-next-line react-hooks/exhaustive-deps
4974
},[modalHeight]);
5075

5176
const{width:detectWidth,height:detectHeight, ref}=useResizeDetector();
52-
// log.info("Modal. modalWidth: ", modalWidth, " width: ", size?.w, " detectWidth: ", detectWidth);
77+
78+
// Memoize Resizable props
79+
constresizableProps=useMemo(()=>({
80+
width:width??detectWidth??0,
81+
height:height??detectHeight??0,
82+
resizeHandles,
83+
handle:Handle,
84+
onResizeStart:handleResizeStart,
85+
onResize:handleResize,
86+
onResizeStop:handleResizeStop
87+
}),[width,detectWidth,height,detectHeight,resizeHandles,handleResizeStart,handleResize,handleResizeStop]);
88+
5389
return(
5490
<AntdModal
5591
width={width??modalWidth}
56-
styles={{
57-
body:{
58-
height:height??modalHeight,
59-
...styles?.body,
60-
}
61-
}}
92+
styles={modalStyles}
6293
{...otherProps}
6394
>
64-
<Resizable
65-
width={width??detectWidth??0}
66-
height={height??detectHeight??0}
67-
resizeHandles={resizeHandles}
68-
handle={Handle}
69-
onResizeStart={(event,{ node, size, handle})=>
70-
props.onResizeStart?.(event,node,size,handle)
71-
}
72-
onResize={(event,{ node, size, handle})=>{
73-
setWidth(size.width);
74-
setHeight(size.height);
75-
props.onResize?.(event,node,size,handle);
76-
}}
77-
onResizeStop={(event,{ node, size, handle})=>
78-
props.onResizeStop?.(event,node,size,handle)
79-
}
80-
>
95+
<Resizable{...resizableProps}>
8196
<divref={ref}style={{height:"100%"}}>
8297
{children}
8398
</div>

‎client/packages/lowcoder-design/src/components/ScrollBar.tsx‎

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
importReactfrom"react";
1+
importReact,{useCallback,useMemo}from"react";
22
importSimpleBarfrom"simplebar-react";
33
importstyledfrom"styled-components";
44
import{DebouncedFunc}from'lodash';// Assuming you're using lodash's DebouncedFunc type
@@ -57,7 +57,7 @@ interface IProps {
5757
children:React.ReactNode;
5858
className?:string;
5959
height?:string;
60-
overflow?:string,
60+
overflow?:string,
6161
style?:React.CSSProperties;// Add this line to include a style prop
6262
scrollableNodeProps?:{
6363
onScroll:DebouncedFunc<(e:any)=>void>;
@@ -68,7 +68,7 @@ interface IProps {
6868
suffixNode?:React.ReactNode;
6969
}
7070

71-
exportconstScrollBar=({
71+
exportconstScrollBar=React.memo(({
7272
className,
7373
children,
7474
style,
@@ -80,31 +80,46 @@ export const ScrollBar = ({
8080
suffixNode,
8181
...otherProps
8282
}:IProps)=>{
83-
constheight=style?.height??'100%';
84-
// You can now use the style prop directly or pass it to SimpleBar
85-
constcombinedStyle={ ...style, height};// Example of combining height with passed style
83+
// Memoize the combined style to prevent unnecessary re-renders
84+
constcombinedStyle=useMemo(()=>{
85+
constheight=style?.height??'100%';
86+
return{ ...style, height};
87+
},[style]);
88+
89+
// Memoize the render function to prevent recreation on every render
90+
constrenderContent=useCallback(({ scrollableNodeProps, contentNodeProps}:any)=>(
91+
<div{...scrollableNodeProps}>
92+
{prefixNode}
93+
<div{...contentNodeProps}>
94+
{children}
95+
</div>
96+
{suffixNode}
97+
</div>
98+
),[prefixNode,children,suffixNode]);
8699

87100
returnhideScrollbar ?(
88-
<ScrollBarWrapperclassName={className}>
101+
<ScrollBarWrapper
102+
className={className}
103+
$hideplaceholder={$hideplaceholder}
104+
$overflow={overflow}
105+
>
89106
{prefixNode}
90107
{children}
91108
{suffixNode}
92109
</ScrollBarWrapper>
93110
) :(
94-
<ScrollBarWrapperclassName={className}>
95-
<SimpleBarstyle={combinedStyle}scrollableNodeProps={scrollableNodeProps}{...otherProps}>
96-
{({ scrollableNodeProps, contentNodeProps})=>{
97-
return(
98-
<div{...scrollableNodePropsasany}>
99-
{prefixNode}
100-
<div{...contentNodePropsasany}>
101-
{children}
102-
</div>
103-
{suffixNode}
104-
</div>
105-
);
106-
}}
111+
<ScrollBarWrapper
112+
className={className}
113+
$hideplaceholder={$hideplaceholder}
114+
$overflow={overflow}
115+
>
116+
<SimpleBar
117+
style={combinedStyle}
118+
scrollableNodeProps={scrollableNodeProps}
119+
{...otherProps}
120+
>
121+
{renderContent}
107122
</SimpleBar>
108123
</ScrollBarWrapper>
109124
);
110-
};
125+
});

‎client/packages/lowcoder-design/src/components/Section.tsx‎

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import{trans}from"i18n/design";
2-
importReact,{ReactNode,useContext}from"react";
2+
importReact,{ReactNode,useContext,useCallback,useMemo}from"react";
33
importstyledfrom"styled-components";
44
import{ReactComponentasPackup}from"icons/v1/icon-Pack-up.svg";
55
import{labelCss}from"./Label";
@@ -14,6 +14,7 @@ const SectionItem = styled.div<{ $width?: number }>`
1414
border-bottom: none;
1515
}
1616
`;
17+
1718
constSectionLabel=styled.div`
1819
${labelCss};
1920
flex-grow: 1;
@@ -64,6 +65,10 @@ const SectionLabelDiv = styled.div`
6465
}
6566
`;
6667

68+
constButtonContainer=styled.div`
69+
display: flex;
70+
`;
71+
6772
constShowChildren=styled.div<{$show?:string;$noMargin?:boolean}>`
6873
display:${(props)=>props.$show||"none"};
6974
flex-direction: column;
@@ -80,6 +85,7 @@ const TooltipWrapper = styled.span`
8085
white-space: pre-wrap;
8186
color:#fff;
8287
`;
88+
8389
interfaceISectionConfig<T>{
8490
name?:string;
8591
open?:boolean;
@@ -109,59 +115,67 @@ export const PropertySectionContext = React.createContext<PropertySectionContext
109115
state:{},
110116
});
111117

112-
exportconstBaseSection=(props:ISectionConfig<ReactNode>)=>{
113-
const{ name,hasTooltip}=props;
118+
constTOOLTIP_CONTENT=(
119+
<TooltipWrapper>
120+
Here you can enter the animation type codes. Like bounce, swing or
121+
tada. Read more about all possible codes at:{" "}
122+
<ahref="https://animate.style">https://animate.style</a>
123+
</TooltipWrapper>
124+
);
125+
126+
exportconstBaseSection=React.memo((props:ISectionConfig<ReactNode>)=>{
127+
const{ name, hasTooltip}=props;
114128
const{ compName, state, toggle}=useContext(PropertySectionContext);
115129
constopen=props.open!==undefined ?props.open :name ?state[compName]?.[name]!==false :true;
116130

117-
// console.log("open", open, props.open);
118-
119-
consthandleToggle=()=>{
131+
consthandleToggle=useCallback(()=>{
120132
if(!name){
121133
return;
122134
}
123135
toggle(compName,name);
124-
};
136+
},[name,compName,toggle]);
137+
138+
consttooltipContent=useMemo(()=>hasTooltip ?TOOLTIP_CONTENT :null,[hasTooltip]);
139+
140+
constgetPopupContainer=useCallback((node:HTMLElement)=>{
141+
return(node.closest('.react-grid-item')asHTMLElement)||document.body;
142+
},[]);
125143

126144
return(
127145
<SectionItem$width={props.width}style={props.style}>
128146
{props.name&&(
129147
<SectionLabelDivonClick={handleToggle}className={'section-header'}>
130148
<SectionLabel>{props.name}</SectionLabel>
131-
<divstyle={{display:'flex'}}>
149+
<ButtonContainer>
132150
{open&&props.additionalButton}
133151
<PackupIcondeg={open ?'rotate(0deg)' :'rotate(180deg)'}/>
134-
</div>
152+
</ButtonContainer>
135153
</SectionLabelDiv>
136154
)}
137155
<Tooltip
138-
title={
139-
hasTooltip&&(
140-
<TooltipWrapper>
141-
Here you can enter the animation type codes. Like bounce, swing or
142-
tada. Read more about all possible codes at:{" "}
143-
<ahref="https://animate.style">https://animate.style</a>
144-
</TooltipWrapper>
145-
)
146-
}
156+
title={tooltipContent}
147157
arrow={{
148158
pointAtCenter:true,
149159
}}
150160
placement="top"
151161
color="#2c2c2c"
152-
getPopupContainer={(node:any)=>node.closest('.react-grid-item')}
162+
getPopupContainer={getPopupContainer}
153163
>
154164
<ShowChildren$show={open ?'flex' :'none'}$noMargin={props.noMargin}>
155165
{props.children}
156166
</ShowChildren>
157167
</Tooltip>
158168
</SectionItem>
159169
);
160-
};
170+
});
161171

162-
exportfunctionSection(props:ISectionConfig<ControlNode>){
172+
BaseSection.displayName='BaseSection';
173+
174+
exportconstSection=React.memo((props:ISectionConfig<ControlNode>)=>{
163175
returncontrolItem({filterText:props.name,searchChild:true},<BaseSection{...props}/>);
164-
}
176+
});
177+
178+
Section.displayName='Section';
165179

166180
// common section names
167181
exportconstsectionNames={

‎client/packages/lowcoder-design/src/components/Tab.tsx‎

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
importstyled,{css}from"styled-components";
2-
importReactfrom"react";
2+
importReact,{useCallback,useMemo}from"react";
33

44
constHeaderDiv=styled.div`
55
width: 312px;
@@ -79,26 +79,42 @@ interface ITabs {
7979
activeKey:string;
8080
}
8181

82-
constTabs=(props:ITabs)=>{
82+
constTabs=React.memo((props:ITabs)=>{
8383
const{ onChange, tabsConfig, activeKey}=props;
84-
constactiveTab=tabsConfig.find((c)=>c.key===activeKey)||tabsConfig[0];
84+
85+
constactiveTab=useMemo(()=>
86+
tabsConfig.find((c)=>c.key===activeKey)||tabsConfig[0],
87+
[tabsConfig,activeKey]
88+
);
89+
90+
consthandleTabClick=useCallback((key:string)=>{
91+
onChange(key);
92+
},[onChange]);
93+
94+
constrenderTab=useCallback((tab:ITabsConfig)=>{
95+
constisActive=activeTab.key===tab.key;
96+
return(
97+
<IconAndName
98+
key={tab.key}
99+
onClick={()=>handleTabClick(tab.key)}
100+
$isActive={isActive}
101+
>
102+
{tab.icon}
103+
<Text$color={isActive ?"#222222" :"#8b8fa3"}>{tab.title}</Text>
104+
</IconAndName>
105+
);
106+
},[activeTab.key,handleTabClick]);
85107

86108
return(
87109
<>
88110
<HeaderDiv>
89-
{props.tabsConfig.map((tab)=>{
90-
constisActive=activeTab.key===tab.key;
91-
return(
92-
<IconAndNamekey={tab.key}onClick={()=>onChange(tab.key)}$isActive={isActive}>
93-
{tab.icon}
94-
<Text$color={isActive ?"#222222" :"#8b8fa3"}>{tab.title}</Text>
95-
</IconAndName>
96-
);
97-
})}
111+
{tabsConfig.map(renderTab)}
98112
</HeaderDiv>
99113
<ChildDiv>{activeTab.content}</ChildDiv>
100114
</>
101115
);
102-
};
116+
});
117+
118+
Tabs.displayName='Tabs';
103119

104120
export{Tabs};

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp