1
- import { useContext , useEffect , useState } from "react" ;
1
+ import React , { useContext , useEffect , useState , useCallback , useMemo } from "react" ;
2
2
import styled from "styled-components" ;
3
3
import { PointIcon , SearchOutlinedIcon } from "lowcoder-design/src/icons" ;
4
4
import type { EditPopoverItemType } from 'lowcoder-design/src/components/popover' ;
@@ -72,89 +72,100 @@ interface Iprops {
72
72
search ?: { searchText : string ; setSearchText : ( t : string ) => void } ;
73
73
}
74
74
75
- export const CompName = ( props : Iprops ) => {
75
+ export const CompName = React . memo ( ( props : Iprops ) => {
76
76
const [ error , setError ] = useState < string | undefined > ( undefined ) ;
77
77
const [ editing , setEditing ] = useState ( false ) ;
78
78
const [ upgrading , setUpgrading ] = useState ( false ) ;
79
+ const [ showSearch , setShowSearch ] = useState < boolean > ( false ) ;
80
+
79
81
const editorState = useContext ( EditorContext ) ;
80
- const selectedComp = values ( editorState . selectedComps ( ) ) [ 0 ] ;
81
- const compType = selectedComp . children . compType . getView ( ) as UICompType ;
82
- const compInfo = parseCompType ( compType ) ;
83
- const docUrl = getComponentDocUrl ( compType ) ;
84
- const playgroundUrl = getComponentPlaygroundUrl ( compType ) ;
85
-
86
- const items : EditPopoverItemType [ ] = [ ] ;
87
-
88
- // Falk: TODO - Implement upgrade for individual Version functionality
89
- const handleUpgrade = async ( ) => {
90
- if ( upgrading ) {
91
- return ;
92
- }
82
+ const selectedComp = useMemo ( ( ) => values ( editorState . selectedComps ( ) ) [ 0 ] , [ editorState ] ) ;
83
+ const compType = useMemo ( ( ) => selectedComp . children . compType . getView ( ) as UICompType , [ selectedComp ] ) ;
84
+ const compInfo = useMemo ( ( ) => parseCompType ( compType ) , [ compType ] ) ;
85
+ const docUrl = useMemo ( ( ) => getComponentDocUrl ( compType ) , [ compType ] ) ;
86
+ const playgroundUrl = useMemo ( ( ) => getComponentPlaygroundUrl ( compType ) , [ compType ] ) ;
87
+
88
+ // Cleanup on unmount
89
+ useEffect ( ( ) => {
90
+ return ( ) => {
91
+ setError ( undefined ) ;
92
+ setEditing ( false ) ;
93
+ setUpgrading ( false ) ;
94
+ setShowSearch ( false ) ;
95
+ } ;
96
+ } , [ ] ) ;
97
+
98
+ // Reset search when name changes
99
+ useEffect ( ( ) => {
100
+ setShowSearch ( false ) ;
101
+ } , [ props . name ] ) ;
102
+
103
+ const handleUpgrade = useCallback ( async ( ) => {
104
+ if ( upgrading ) return ;
93
105
setUpgrading ( true ) ;
94
- await GridCompOperator . upgradeCurrentComp ( editorState ) ;
95
- setUpgrading ( false ) ;
96
- } ;
97
-
98
- if ( docUrl ) {
99
- items . push ( {
100
- text : trans ( "comp.menuViewDocs" ) ,
101
- onClick : ( ) => {
102
- window . open ( docUrl , "_blank" ) ;
103
- } ,
104
- } ) ;
105
- }
106
+ try {
107
+ await GridCompOperator . upgradeCurrentComp ( editorState ) ;
108
+ } finally {
109
+ setUpgrading ( false ) ;
110
+ }
111
+ } , [ upgrading , editorState ] ) ;
106
112
107
- if ( playgroundUrl ) {
108
- items . push ( {
109
- text : trans ( "comp.menuViewPlayground" ) ,
110
- onClick : ( ) => {
111
- window . open ( playgroundUrl , "_blank" ) ;
112
- } ,
113
- } ) ;
114
- }
113
+ const handleRename = useCallback ( ( value : string ) => {
114
+ if ( editorState . rename ( props . name , value ) ) {
115
+ editorState . setSelectedCompNames ( new Set ( [ value ] ) ) ;
116
+ setError ( undefined ) ;
117
+ }
118
+ } , [ editorState , props . name ] ) ;
115
119
120
+ const handleSearchChange = useCallback ( ( e : React . ChangeEvent < HTMLInputElement > ) => {
121
+ props . search ?. setSearchText ( e . target . value ) ;
122
+ } , [ props . search ] ) ;
116
123
117
- if ( compInfo . isRemote ) {
118
- // Falk: Displaying the current version of the component
119
- items . push ( {
120
- text : trans ( "history.currentVersion" ) + ": " + compInfo . packageVersion ,
121
- onClick : ( ) => {
122
- } ,
123
- } ) ;
124
- // items.push({
125
- // text: trans("history.currentVersion") + ": " + compInfo.packageVersion,
126
- // onClick: () => {
127
-
128
- // },
129
- // });
130
-
131
- items . push ( {
132
- text : trans ( "comp.menuUpgradeToLatest" ) ,
133
- onClick : ( ) => {
134
- handleUpgrade ( ) ;
135
- } ,
136
-
137
- } ) ;
138
- }
124
+ const handleSearchToggle = useCallback ( ( ) => {
125
+ setShowSearch ( prev => ! prev ) ;
126
+ props . search ?. setSearchText ( "" ) ;
127
+ } , [ props . search ] ) ;
139
128
140
- const [ showSearch , setShowSearch ] = useState < boolean > ( false ) ;
141
- const { search } = props ;
142
- useEffect ( ( ) => {
143
- setShowSearch ( false ) ;
144
- } , [ props . name ] ) ;
145
- const compName = (
146
- < CompDiv $width = { props . width } $hasSearch = { ! ! search } $showSearch = { showSearch } >
129
+ const items = useMemo < EditPopoverItemType [ ] > ( ( ) => {
130
+ const menuItems : EditPopoverItemType [ ] = [ ] ;
131
+
132
+ if ( docUrl ) {
133
+ menuItems . push ( {
134
+ text : trans ( "comp.menuViewDocs" ) ,
135
+ onClick : ( ) => window . open ( docUrl , "_blank" ) ,
136
+ } ) ;
137
+ }
138
+
139
+ if ( playgroundUrl ) {
140
+ menuItems . push ( {
141
+ text : trans ( "comp.menuViewPlayground" ) ,
142
+ onClick : ( ) => window . open ( playgroundUrl , "_blank" ) ,
143
+ } ) ;
144
+ }
145
+
146
+ if ( compInfo . isRemote ) {
147
+ menuItems . push ( {
148
+ text : trans ( "history.currentVersion" ) + ": " + compInfo . packageVersion ,
149
+ onClick : ( ) => { } ,
150
+ } ) ;
151
+
152
+ menuItems . push ( {
153
+ text : trans ( "comp.menuUpgradeToLatest" ) ,
154
+ onClick : handleUpgrade ,
155
+ } ) ;
156
+ }
157
+
158
+ return menuItems ;
159
+ } , [ docUrl , playgroundUrl , compInfo , handleUpgrade ] ) ;
160
+
161
+ const compName = useMemo ( ( ) => (
162
+ < CompDiv $width = { props . width } $hasSearch = { ! ! props . search } $showSearch = { showSearch } >
147
163
< div >
148
164
< EditText
149
165
text = { props . name }
150
- onFinish = { ( value ) => {
151
- if ( editorState . rename ( props . name , value ) ) {
152
- editorState . setSelectedCompNames ( new Set ( [ value ] ) ) ;
153
- setError ( undefined ) ;
154
- }
155
- } }
166
+ onFinish = { handleRename }
156
167
onChange = { ( value ) => setError ( editorState . checkRename ( props . name , value ) ) }
157
- onEditStateChange = { ( editing ) => setEditing ( editing ) }
168
+ onEditStateChange = { setEditing }
158
169
/>
159
170
< PopupCard
160
171
editorFocus = { ! ! error && editing }
@@ -163,16 +174,13 @@ export const CompName = (props: Iprops) => {
163
174
hasError = { ! ! error }
164
175
/>
165
176
</ div >
166
- { ! ! search && (
177
+ { ! ! props . search && (
167
178
< SearchIcon
168
- onClick = { ( ) => {
169
- setShowSearch ( ! showSearch ) ;
170
- search ?. setSearchText ( "" ) ;
171
- } }
179
+ onClick = { handleSearchToggle }
172
180
style = { { color : showSearch ? "#315EFB" : "#8B8FA3" } }
173
181
/>
174
182
) }
175
- { compType === "module" ? (
183
+ { compType === "module" ? (
176
184
< EditPopover
177
185
items = { items }
178
186
edit = { ( ) => GridCompOperator . editComp ( editorState ) }
@@ -189,19 +197,32 @@ export const CompName = (props: Iprops) => {
189
197
</ EditPopover >
190
198
) }
191
199
</ CompDiv >
192
- ) ;
200
+ ) , [
201
+ props . width ,
202
+ props . search ,
203
+ props . name ,
204
+ showSearch ,
205
+ error ,
206
+ editing ,
207
+ compType ,
208
+ items ,
209
+ editorState ,
210
+ handleRename ,
211
+ handleSearchToggle
212
+ ] ) ;
213
+
193
214
return (
194
215
< div >
195
216
{ compName }
196
- { search && showSearch && (
217
+ { props . search && showSearch && (
197
218
< Search
198
219
placeholder = { trans ( "comp.searchProp" ) }
199
- value = { search . searchText }
200
- onChange = { ( e ) => search . setSearchText ( e . target . value ) }
220
+ value = { props . search . searchText }
221
+ onChange = { handleSearchChange }
201
222
allowClear = { true }
202
223
style = { { padding : "0 16px" , margin : "0 0 4px 0" } }
203
224
/>
204
225
) }
205
226
</ div >
206
227
) ;
207
- } ;
228
+ } ) ;
0 commit comments