@@ -41,6 +41,32 @@ const scriptListSorter = (a: ScriptMenu, b: ScriptMenu) =>
4141 b . runNum - a . runNum ||
4242 b . updatetime - a . updatetime ;
4343
44+ type TUpdateEntryFn = ( item : ScriptMenu ) => ScriptMenu | undefined ;
45+
46+ type TUpdateListOption = { sort ?: boolean } ;
47+
48+ const updateList = ( list : ScriptMenu [ ] , update : TUpdateEntryFn , options : TUpdateListOption | undefined ) => {
49+ // 如果更新跟当前 list 的子项无关,则不用更改 list 的物件参考
50+ const newList : ScriptMenu [ ] = [ ] ;
51+ let changed = false ;
52+ for ( let i = 0 ; i < list . length ; i ++ ) {
53+ const oldItem = list [ i ] ;
54+ const newItem = update ( oldItem ) ; // 如没有更改,物件参考会保持一致
55+ if ( newItem !== oldItem ) changed = true ;
56+ if ( newItem ) {
57+ newList . push ( newItem ) ;
58+ }
59+ }
60+ if ( options ?. sort ) {
61+ newList . sort ( scriptListSorter ) ;
62+ }
63+ if ( ! changed && list . map ( ( e ) => e . uuid ) . join ( "," ) !== newList . map ( ( e ) => e . uuid ) . join ( "," ) ) {
64+ // 单一项未有改变,但因为 sort值改变 而改变了次序
65+ changed = true ;
66+ }
67+ return changed ? newList : list ; // 如子项没任何变化,则返回原list参考
68+ } ;
69+
4470function App ( ) {
4571 const [ loading , setLoading ] = useState ( true ) ;
4672 const [ scriptList , setScriptList ] = useState < ( ScriptMenu & { menuUpdated ?: number } ) [ ] > ( [ ] ) ;
@@ -59,23 +85,48 @@ function App() {
5985 const { t } = useTranslation ( ) ;
6086 const pageTabIdRef = useRef ( 0 ) ;
6187
88+ // ------------------------------ 重要! 不要隨便更改 ------------------------------
89+ // > scriptList 會隨著 (( 任何 )) 子項狀態更新而進行物件參考更新
90+ // > (( 必須 )) 把物件參考更新切換成 原始类型(例如字串)
91+
92+ // normalEnables: 只随 script 数量和启动状态而改变的state
93+ // 故意生成一个字串 memo 避免因 scriptList 的参考频繁改动而导致 normalScriptCounts 的物件参考出现非预期更改。
94+ const normalEnables = useMemo ( ( ) => {
95+ // 返回字串让 React 比对 state 有否改动
96+ return scriptList . map ( ( script ) => ( script . enable ? 1 : 0 ) ) . join ( "," ) ;
97+ } , [ scriptList ] ) ;
98+
99+ // backEnables: 只随 script 数量和启动状态而改变的state
100+ // 故意生成一个字串 memo 避免因 scriptList 的参考频繁改动而导致 backScriptCounts 的物件参考出现非预期更改。
101+ const backEnables = useMemo ( ( ) => {
102+ // 返回字串让 React 比对 state 有否改动
103+ return backScriptList . map ( ( script ) => ( script . enable ? 1 : 0 ) ) . join ( "," ) ;
104+ } , [ backScriptList ] ) ;
105+ // ------------------------------ 重要! 不要隨便更改 ------------------------------
106+
107+ // normalScriptCounts 的物件參考只會隨 原始类型(字串)的 normalEnables 狀態更新而重新生成
62108 const normalScriptCounts = useMemo ( ( ) => {
109+ // 拆回array
110+ const enables = normalEnables . split ( "," ) . filter ( Boolean ) ;
63111 // 计算已开启了的数量
64- const running = scriptList . reduce ( ( p , c ) => p + ( c . enable ? 1 : 0 ) , 0 ) ;
112+ const running = enables . reduce ( ( p , c ) => p + ( + c ? 1 : 0 ) , 0 ) ;
65113 return {
66114 running,
67- total : scriptList . length , // 总数
115+ total : enables . length , // 总数
68116 } ;
69- } , [ scriptList ] ) ;
117+ } , [ normalEnables ] ) ;
70118
119+ // backScriptCounts 的物件參考只會隨 原始类型(字串)的 backEnables 狀態更新而重新生成
71120 const backScriptCounts = useMemo ( ( ) => {
121+ // 拆回array
122+ const enables = backEnables . split ( "," ) . filter ( Boolean ) ;
72123 // 计算已开启了的数量
73- const running = backScriptList . reduce ( ( p , c ) => p + ( c . enable ? 1 : 0 ) , 0 ) ;
124+ const running = enables . reduce ( ( p , c ) => p + ( + c ? 1 : 0 ) , 0 ) ;
74125 return {
75126 running,
76- total : backScriptList . length , // 总数
127+ total : enables . length , // 总数
77128 } ;
78- } , [ backScriptList ] ) ;
129+ } , [ backEnables ] ) ;
79130
80131 const urlHost = useMemo ( ( ) => {
81132 let url : URL | undefined ;
@@ -91,31 +142,10 @@ function App() {
91142 useEffect ( ( ) => {
92143 let isMounted = true ;
93144
94- const updateScriptList = (
95- update : ( item : ScriptMenu ) => ScriptMenu | undefined ,
96- options ?: {
97- sort ?: boolean ;
98- }
99- ) => {
100- const updateList = ( list : ScriptMenu [ ] , update : ( item : ScriptMenu ) => ScriptMenu | undefined ) => {
101- const newList = [ ] ;
102- for ( let i = 0 ; i < list . length ; i ++ ) {
103- const newItem = update ( list [ i ] ) ;
104- if ( newItem ) {
105- newList . push ( newItem ) ;
106- }
107- }
108- if ( options ?. sort ) {
109- newList . sort ( scriptListSorter ) ;
110- }
111- return newList ;
112- } ;
113- setScriptList ( ( prev ) => {
114- return updateList ( prev , update ) ;
115- } ) ;
116- setBackScriptList ( ( prev ) => {
117- return updateList ( prev , update ) ;
118- } ) ;
145+ const updateScriptList = ( update : TUpdateEntryFn , options ?: TUpdateListOption ) => {
146+ // 当 启用/禁用/菜单改变 时,如有必要则更新 list 参考
147+ setScriptList ( ( prev ) => updateList ( prev , update , options ) ) ;
148+ setBackScriptList ( ( prev ) => updateList ( prev , update , options ) ) ;
119149 } ;
120150
121151 const unhooks = [
0 commit comments