@canlooks/can-ui 0.0.176 → 0.0.177

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,7 +14,7 @@ exports.AnchorList = (0, react_1.memo)(({ anchors, renderAnchorItem, indent = 24
14
14
  * 初始化高亮与滚动位置
15
15
  */
16
16
  const mounted = (0, react_1.useRef)(false);
17
- (0, utils_1.useExternalClass)(() => {
17
+ (0, react_1.useEffect)(() => {
18
18
  if (routeMode === 'history') {
19
19
  mounted.current ||= scrollToId(location.hash.slice(1));
20
20
  }
@@ -15,10 +15,11 @@ export declare function useAppContext(): {
15
15
  notification: AppNotificationMethods<import("./appNotification").AppNotificationProps>;
16
16
  actionSheet: AppActionSheetMethods;
17
17
  };
18
- export declare const App: OverridableComponent<AppOwnProps> & {
18
+ export type AppMethods = {
19
19
  dialog: AppDialogMethods;
20
20
  message: AppMessageMethods;
21
21
  notification: AppNotificationMethods;
22
22
  actionSheet: AppActionSheetMethods;
23
23
  };
24
+ export declare const App: OverridableComponent<AppOwnProps> & AppMethods;
24
25
  export declare function InnerApp({ component: Component, theme, children, fill, ...props }: OverridableProps<AppProps, 'div'>): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -27,17 +27,12 @@ exports.App = (({ theme, ...props }) => {
27
27
  return ((0, jsx_runtime_1.jsx)(globalEventDelegation_1.GlobalEventDelegation, { children: (0, jsx_runtime_1.jsx)(theme_1.ThemeProvider, { theme: theme, children: (0, jsx_runtime_1.jsx)(InnerApp, { ...props }) }) }));
28
28
  });
29
29
  function InnerApp({ component: Component = 'div', theme, children, fill = true, ...props }) {
30
- const appValue = (0, utils_1.useExternalClass)(() => ({
31
- dialog: new appDialog_1.AppDialogMethods(),
32
- message: new appMessage_1.AppMessageMethods(),
33
- notification: new appNotification_1.AppNotificationMethods(),
34
- actionSheet: new appActionSheet_1.AppActionSheetMethods()
35
- }));
36
- exports.App.dialog ||= appValue.dialog;
37
- exports.App.message ||= appValue.message;
38
- exports.App.notification ||= appValue.notification;
39
- exports.App.actionSheet ||= appValue.actionSheet;
40
- return ((0, jsx_runtime_1.jsxs)(AppContext, { value: appValue, children: [Component
30
+ const appContext = useAppContext();
31
+ exports.App.dialog = appContext.dialog;
32
+ exports.App.message = appContext.message;
33
+ exports.App.notification = appContext.notification;
34
+ exports.App.actionSheet = appContext.actionSheet;
35
+ return ((0, jsx_runtime_1.jsxs)(AppContext, { value: appContext, children: [Component
41
36
  ? (0, jsx_runtime_1.jsx)(Component, { ...props, css: [
42
37
  app_style_1.style,
43
38
  (0, utils_1.defineCss)(({ background }) => (0, react_2.css) `
@@ -49,5 +44,5 @@ function InnerApp({ component: Component = 'div', theme, children, fill = true,
49
44
  flex: 1;
50
45
  `
51
46
  ], className: (0, utils_1.clsx)(app_style_1.classes.root, props.className), children: children })
52
- : children, (0, jsx_runtime_1.jsx)(appDialog_1.AppDialog, { methods: appValue.dialog }), (0, jsx_runtime_1.jsx)(appMessage_1.AppMessage, { methods: appValue.message }), (0, jsx_runtime_1.jsx)(appNotification_1.AppNotification, { methods: appValue.notification }), (0, jsx_runtime_1.jsx)(appActionSheet_1.AppActionSheet, { methods: appValue.actionSheet })] }));
47
+ : children, (0, jsx_runtime_1.jsx)(appDialog_1.AppDialog, { methods: appContext.dialog }), (0, jsx_runtime_1.jsx)(appMessage_1.AppMessage, { methods: appContext.message }), (0, jsx_runtime_1.jsx)(appNotification_1.AppNotification, { methods: appContext.notification }), (0, jsx_runtime_1.jsx)(appActionSheet_1.AppActionSheet, { methods: appContext.actionSheet })] }));
53
48
  }
@@ -17,7 +17,7 @@ exports.Autocomplete = (0, react_1.memo)(({ children, loading, options, loadOpti
17
17
  };
18
18
  const [innerValue, setInnerValue] = (0, utils_1.useControlled)(defaultValue, value);
19
19
  const changedBySelect = (0, react_1.useRef)(false);
20
- const changeHandler = (e, isSelect = false) => {
20
+ const changeHandler = (e, isSelect) => {
21
21
  changedBySelect.current = isSelect;
22
22
  onChange?.(e);
23
23
  setInnerValue(e.target.value);
@@ -80,7 +80,7 @@ exports.Autocomplete = (0, react_1.memo)(({ children, loading, options, loadOpti
80
80
  className: autocomplete_style_1.classes.root,
81
81
  loading: innerLoading.current,
82
82
  value: innerValue.current,
83
- onChange: changeHandler,
83
+ onChange: e => changeHandler(e, false),
84
84
  onFocus: () => setFocused(true),
85
85
  onBlur: () => setFocused(false)
86
86
  });
@@ -33,7 +33,7 @@ const Waterfall = ({ columnCount = { xs: 4 }, gap = 0, columnGap, rowGap, ...pro
33
33
  });
34
34
  });
35
35
  (0, utils_1.useUpdateEffect)(computeItemOrder, [columnCountNum.current]);
36
- (0, utils_1.useExternalClass)(() => void 0, () => {
36
+ (0, utils_1.useUnmounted)(() => {
37
37
  resizeObserver.current.disconnect();
38
38
  });
39
39
  return ((0, jsx_runtime_1.jsx)("div", { ...props, ref: (0, utils_1.cloneRef)(containerRef, props.ref), css: (0, waterfall_style_1.useStyle)({ columnCount, columnGap, rowGap }), className: (0, utils_1.clsx)(waterfall_style_1.classes.root, props.className), children: react_1.Children.map(props.children, child => {
@@ -26,6 +26,10 @@ function InnerFormItem({ dependencies, checked, value, onChange, ...props }) {
26
26
  props.children.props?.onChange?.(e);
27
27
  onChange?.(e);
28
28
  context.onChange?.();
29
+ },
30
+ onkeydown(e) {
31
+ e.preventDefault();
32
+ props.children.props?.onkeydown?.(e);
29
33
  }
30
34
  };
31
35
  return ((0, jsx_runtime_1.jsx)(form_1.FormItem, { ...props, ref: (0, utils_1.cloneRef)(formItemRef, props.ref), _fieldValue: checked ?? value, children: (_, styleProps, key) => {
@@ -24,10 +24,10 @@ export declare function useDerivedState<T>(referredState: (prevState: T | undefi
24
24
  export declare function useDerivedState<T>(referredState: T, deps?: any[]): [RefObject<T>, Dispatch<SetStateAction<T>>];
25
25
  export declare function useMounted(): void;
26
26
  /**
27
- * 组件卸载后得到{current: true}
28
- * @returns
27
+ * 得到一个RefObject,用于判断组件是否卸载
28
+ * @param onUnmount 回调函数,卸载时触发
29
29
  */
30
- export declare function useUnmounted(): RefObject<boolean>;
30
+ export declare function useUnmounted(onUnmount?: () => void): RefObject<boolean>;
31
31
  /**
32
32
  * 处理受控组件的外部属性与内部属性
33
33
  * @param defaultValue
@@ -55,7 +55,7 @@ export declare function useContainer<T extends HTMLElement | null>(container?: D
55
55
  /**
56
56
  * 使用外部类,该方法可避免`StrictMode`下,React渲染行为与外部类实例生命周期不同步的问题
57
57
  */
58
- export declare function useExternalClass<T>(setup: () => T, cleanup?: (instance: T) => void): T;
58
+ export declare function useExternalClass<T>(setup: () => T, cleanup?: (instance: T) => void): RefObject<T>;
59
59
  /**
60
60
  * 用法同{@link useEffect},但StrictMode下不会执行两次
61
61
  */
@@ -67,4 +67,4 @@ export declare function useUpdateEffect(effect: EffectCallback, deps?: Dependenc
67
67
  /**
68
68
  * 用法同{@link useMemo},但StrictMode下不会执行两次
69
69
  */
70
- export declare function useStrictMemo<T>(factory: () => T, deps?: DependencyList): T | undefined;
70
+ export declare function useStrictMemo<T>(factory: () => T, deps: DependencyList): T | undefined;
@@ -47,7 +47,7 @@ function useForceUpdate() {
47
47
  function useDerivedState(referredState, deps) {
48
48
  const derivedState = (0, react_1.useRef)(void 0);
49
49
  (0, react_1.useMemo)(() => {
50
- // StrictMode下,derivedState会重置2
50
+ // StrictMode下,需要重置2次,使prevState保持正确
51
51
  derivedState.current = void 0;
52
52
  }, []);
53
53
  const updateState = (state) => {
@@ -73,14 +73,21 @@ function useDerivedState(referredState, deps) {
73
73
  function useMounted() {
74
74
  }
75
75
  /**
76
- * 组件卸载后得到{current: true}
77
- * @returns
76
+ * 得到一个RefObject,用于判断组件是否卸载
77
+ * @param onUnmount 回调函数,卸载时触发
78
78
  */
79
- function useUnmounted() {
79
+ function useUnmounted(onUnmount) {
80
80
  const isUnmounted = (0, react_1.useRef)(false);
81
- useExternalClass(() => void 0, () => {
82
- isUnmounted.current = true;
83
- });
81
+ const mountTimes = (0, react_1.useRef)(0);
82
+ (0, react_1.useMemo)(() => {
83
+ mountTimes.current++;
84
+ }, []);
85
+ (0, react_1.useEffect)(() => () => {
86
+ if (!--mountTimes.current) {
87
+ isUnmounted.current = true;
88
+ onUnmount?.();
89
+ }
90
+ }, []);
84
91
  return isUnmounted;
85
92
  }
86
93
  function useControlled(defaultValue, value, onChange) {
@@ -152,31 +159,34 @@ function useContainer(container, effectContainer, defaultContainer) {
152
159
  * 使用外部类,该方法可避免`StrictMode`下,React渲染行为与外部类实例生命周期不同步的问题
153
160
  */
154
161
  function useExternalClass(setup, cleanup) {
155
- const mountTimes = (0, react_1.useRef)(0);
156
- const prevInstance = (0, react_1.useRef)(void 0);
157
- const [instance] = (0, react_1.useState)(() => {
158
- if (!mountTimes.current++) {
159
- prevInstance.current = setup();
160
- }
161
- return prevInstance.current;
162
+ const instance = (0, react_1.useRef)(void 0);
163
+ instance.current ||= setup();
164
+ useUnmounted(() => {
165
+ cleanup?.(instance.current);
166
+ instance.current = void 0;
162
167
  });
163
- (0, react_1.useEffect)(() => () => {
164
- !--mountTimes.current && cleanup?.(instance);
165
- }, []);
166
168
  return instance;
167
169
  }
168
170
  /**
169
171
  * 用法同{@link useEffect},但StrictMode下不会执行两次
170
172
  */
171
173
  function useStrictEffect(effect, deps) {
172
- const prevDeps = (0, react_1.useRef)(void 0);
174
+ const hasRun = (0, react_1.useRef)(false);
175
+ const prevDeps = (0, react_1.useRef)(deps);
176
+ const prevCleanup = (0, react_1.useRef)(void 0);
173
177
  (0, react_1.useEffect)(() => {
174
- const isDepsChanged = prevDeps.current ? !(0, utils_1.arrayShallowEqual)(prevDeps.current, deps) : true;
175
- if (isDepsChanged) {
178
+ const isDepsChanged = !(0, utils_1.arrayShallowEqual)(prevDeps.current, deps);
179
+ if (!hasRun.current || isDepsChanged) {
180
+ prevCleanup.current?.();
181
+ prevCleanup.current = effect();
182
+ hasRun.current = true;
176
183
  prevDeps.current = deps;
177
- return effect();
178
184
  }
179
185
  });
186
+ useUnmounted(() => {
187
+ prevCleanup.current?.();
188
+ prevCleanup.current = void 0;
189
+ });
180
190
  }
181
191
  /**
182
192
  * 用法同{@link useEffect},但会排除首次渲染
@@ -200,7 +210,7 @@ function useStrictMemo(factory, deps) {
200
210
  const isDepsChanged = prevDeps.current ? !(0, utils_1.arrayShallowEqual)(prevDeps.current, deps) : true;
201
211
  if (isDepsChanged) {
202
212
  prevDeps.current = deps;
203
- return memoizedValue.current = factory();
213
+ memoizedValue.current = factory();
204
214
  }
205
215
  return memoizedValue.current;
206
216
  }
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
2
  import { classes, style } from './anchorList.style.js';
3
- import { clsx, listenAllPredecessorsScroll, useDerivedState, useExternalClass, useSyncState } from '../../utils/index.js';
3
+ import { clsx, listenAllPredecessorsScroll, useDerivedState, useSyncState } from '../../utils/index.js';
4
4
  import { memo, useEffect, useRef } from 'react';
5
5
  import { Flex } from '../flex/index.js';
6
6
  import { ActiveIndicator } from './activeIndicator.js';
@@ -11,7 +11,7 @@ export const AnchorList = memo(({ anchors, renderAnchorItem, indent = 24, scroll
11
11
  * 初始化高亮与滚动位置
12
12
  */
13
13
  const mounted = useRef(false);
14
- useExternalClass(() => {
14
+ useEffect(() => {
15
15
  if (routeMode === 'history') {
16
16
  mounted.current ||= scrollToId(location.hash.slice(1));
17
17
  }
@@ -15,10 +15,11 @@ export declare function useAppContext(): {
15
15
  notification: AppNotificationMethods<import("./appNotification.js").AppNotificationProps>;
16
16
  actionSheet: AppActionSheetMethods;
17
17
  };
18
- export declare const App: OverridableComponent<AppOwnProps> & {
18
+ export type AppMethods = {
19
19
  dialog: AppDialogMethods;
20
20
  message: AppMessageMethods;
21
21
  notification: AppNotificationMethods;
22
22
  actionSheet: AppActionSheetMethods;
23
23
  };
24
+ export declare const App: OverridableComponent<AppOwnProps> & AppMethods;
24
25
  export declare function InnerApp({ component: Component, theme, children, fill, ...props }: OverridableProps<AppProps, 'div'>): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
2
  import { createContext, useContext } from 'react';
3
- import { clsx, defineCss, useExternalClass } from '../../utils/index.js';
3
+ import { clsx, defineCss } from '../../utils/index.js';
4
4
  import { classes, style } from './app.style.js';
5
5
  import { ThemeProvider } from '../theme/index.js';
6
6
  import { AppDialog, AppDialogMethods } from './appDialog.js';
@@ -22,17 +22,12 @@ export const App = (({ theme, ...props }) => {
22
22
  return (_jsx(GlobalEventDelegation, { children: _jsx(ThemeProvider, { theme: theme, children: _jsx(InnerApp, { ...props }) }) }));
23
23
  });
24
24
  export function InnerApp({ component: Component = 'div', theme, children, fill = true, ...props }) {
25
- const appValue = useExternalClass(() => ({
26
- dialog: new AppDialogMethods(),
27
- message: new AppMessageMethods(),
28
- notification: new AppNotificationMethods(),
29
- actionSheet: new AppActionSheetMethods()
30
- }));
31
- App.dialog ||= appValue.dialog;
32
- App.message ||= appValue.message;
33
- App.notification ||= appValue.notification;
34
- App.actionSheet ||= appValue.actionSheet;
35
- return (_jsxs(AppContext, { value: appValue, children: [Component
25
+ const appContext = useAppContext();
26
+ App.dialog = appContext.dialog;
27
+ App.message = appContext.message;
28
+ App.notification = appContext.notification;
29
+ App.actionSheet = appContext.actionSheet;
30
+ return (_jsxs(AppContext, { value: appContext, children: [Component
36
31
  ? _jsx(Component, { ...props, css: [
37
32
  style,
38
33
  defineCss(({ background }) => css `
@@ -44,5 +39,5 @@ export function InnerApp({ component: Component = 'div', theme, children, fill =
44
39
  flex: 1;
45
40
  `
46
41
  ], className: clsx(classes.root, props.className), children: children })
47
- : children, _jsx(AppDialog, { methods: appValue.dialog }), _jsx(AppMessage, { methods: appValue.message }), _jsx(AppNotification, { methods: appValue.notification }), _jsx(AppActionSheet, { methods: appValue.actionSheet })] }));
42
+ : children, _jsx(AppDialog, { methods: appContext.dialog }), _jsx(AppMessage, { methods: appContext.message }), _jsx(AppNotification, { methods: appContext.notification }), _jsx(AppActionSheet, { methods: appContext.actionSheet })] }));
48
43
  }
@@ -14,7 +14,7 @@ export const Autocomplete = memo(({ children, loading, options, loadOptions, pri
14
14
  };
15
15
  const [innerValue, setInnerValue] = useControlled(defaultValue, value);
16
16
  const changedBySelect = useRef(false);
17
- const changeHandler = (e, isSelect = false) => {
17
+ const changeHandler = (e, isSelect) => {
18
18
  changedBySelect.current = isSelect;
19
19
  onChange?.(e);
20
20
  setInnerValue(e.target.value);
@@ -77,7 +77,7 @@ export const Autocomplete = memo(({ children, loading, options, loadOptions, pri
77
77
  className: classes.root,
78
78
  loading: innerLoading.current,
79
79
  value: innerValue.current,
80
- onChange: changeHandler,
80
+ onChange: e => changeHandler(e, false),
81
81
  onFocus: () => setFocused(true),
82
82
  onBlur: () => setFocused(false)
83
83
  });
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "@emotion/react/jsx-runtime";
2
2
  import { Children, isValidElement, useLayoutEffect, useRef } from 'react';
3
3
  import { classes, useStyle } from './waterfall.style.js';
4
4
  import { WaterfallItem } from './waterfallItem.js';
5
- import { cloneRef, clsx, toResponsiveValue, useExternalClass, useResponsiveValue, useUpdateEffect } from '../../utils/index.js';
5
+ import { cloneRef, clsx, toResponsiveValue, useResponsiveValue, useUnmounted, useUpdateEffect } from '../../utils/index.js';
6
6
  export const Waterfall = ({ columnCount = { xs: 4 }, gap = 0, columnGap, rowGap, ...props }) => {
7
7
  columnCount = toResponsiveValue(columnCount);
8
8
  gap = toResponsiveValue(gap);
@@ -30,7 +30,7 @@ export const Waterfall = ({ columnCount = { xs: 4 }, gap = 0, columnGap, rowGap,
30
30
  });
31
31
  });
32
32
  useUpdateEffect(computeItemOrder, [columnCountNum.current]);
33
- useExternalClass(() => void 0, () => {
33
+ useUnmounted(() => {
34
34
  resizeObserver.current.disconnect();
35
35
  });
36
36
  return (_jsx("div", { ...props, ref: cloneRef(containerRef, props.ref), css: useStyle({ columnCount, columnGap, rowGap }), className: clsx(classes.root, props.className), children: Children.map(props.children, child => {
@@ -23,6 +23,10 @@ function InnerFormItem({ dependencies, checked, value, onChange, ...props }) {
23
23
  props.children.props?.onChange?.(e);
24
24
  onChange?.(e);
25
25
  context.onChange?.();
26
+ },
27
+ onkeydown(e) {
28
+ e.preventDefault();
29
+ props.children.props?.onkeydown?.(e);
26
30
  }
27
31
  };
28
32
  return (_jsx(FormItem, { ...props, ref: cloneRef(formItemRef, props.ref), _fieldValue: checked ?? value, children: (_, styleProps, key) => {
@@ -24,10 +24,10 @@ export declare function useDerivedState<T>(referredState: (prevState: T | undefi
24
24
  export declare function useDerivedState<T>(referredState: T, deps?: any[]): [RefObject<T>, Dispatch<SetStateAction<T>>];
25
25
  export declare function useMounted(): void;
26
26
  /**
27
- * 组件卸载后得到{current: true}
28
- * @returns
27
+ * 得到一个RefObject,用于判断组件是否卸载
28
+ * @param onUnmount 回调函数,卸载时触发
29
29
  */
30
- export declare function useUnmounted(): RefObject<boolean>;
30
+ export declare function useUnmounted(onUnmount?: () => void): RefObject<boolean>;
31
31
  /**
32
32
  * 处理受控组件的外部属性与内部属性
33
33
  * @param defaultValue
@@ -55,7 +55,7 @@ export declare function useContainer<T extends HTMLElement | null>(container?: D
55
55
  /**
56
56
  * 使用外部类,该方法可避免`StrictMode`下,React渲染行为与外部类实例生命周期不同步的问题
57
57
  */
58
- export declare function useExternalClass<T>(setup: () => T, cleanup?: (instance: T) => void): T;
58
+ export declare function useExternalClass<T>(setup: () => T, cleanup?: (instance: T) => void): RefObject<T>;
59
59
  /**
60
60
  * 用法同{@link useEffect},但StrictMode下不会执行两次
61
61
  */
@@ -67,4 +67,4 @@ export declare function useUpdateEffect(effect: EffectCallback, deps?: Dependenc
67
67
  /**
68
68
  * 用法同{@link useMemo},但StrictMode下不会执行两次
69
69
  */
70
- export declare function useStrictMemo<T>(factory: () => T, deps?: DependencyList): T | undefined;
70
+ export declare function useStrictMemo<T>(factory: () => T, deps: DependencyList): T | undefined;
@@ -32,7 +32,7 @@ export function useForceUpdate() {
32
32
  export function useDerivedState(referredState, deps) {
33
33
  const derivedState = useRef(void 0);
34
34
  useMemo(() => {
35
- // StrictMode下,derivedState会重置2
35
+ // StrictMode下,需要重置2次,使prevState保持正确
36
36
  derivedState.current = void 0;
37
37
  }, []);
38
38
  const updateState = (state) => {
@@ -58,14 +58,21 @@ export function useDerivedState(referredState, deps) {
58
58
  export function useMounted() {
59
59
  }
60
60
  /**
61
- * 组件卸载后得到{current: true}
62
- * @returns
61
+ * 得到一个RefObject,用于判断组件是否卸载
62
+ * @param onUnmount 回调函数,卸载时触发
63
63
  */
64
- export function useUnmounted() {
64
+ export function useUnmounted(onUnmount) {
65
65
  const isUnmounted = useRef(false);
66
- useExternalClass(() => void 0, () => {
67
- isUnmounted.current = true;
68
- });
66
+ const mountTimes = useRef(0);
67
+ useMemo(() => {
68
+ mountTimes.current++;
69
+ }, []);
70
+ useEffect(() => () => {
71
+ if (!--mountTimes.current) {
72
+ isUnmounted.current = true;
73
+ onUnmount?.();
74
+ }
75
+ }, []);
69
76
  return isUnmounted;
70
77
  }
71
78
  export function useControlled(defaultValue, value, onChange) {
@@ -137,31 +144,34 @@ export function useContainer(container, effectContainer, defaultContainer) {
137
144
  * 使用外部类,该方法可避免`StrictMode`下,React渲染行为与外部类实例生命周期不同步的问题
138
145
  */
139
146
  export function useExternalClass(setup, cleanup) {
140
- const mountTimes = useRef(0);
141
- const prevInstance = useRef(void 0);
142
- const [instance] = useState(() => {
143
- if (!mountTimes.current++) {
144
- prevInstance.current = setup();
145
- }
146
- return prevInstance.current;
147
+ const instance = useRef(void 0);
148
+ instance.current ||= setup();
149
+ useUnmounted(() => {
150
+ cleanup?.(instance.current);
151
+ instance.current = void 0;
147
152
  });
148
- useEffect(() => () => {
149
- !--mountTimes.current && cleanup?.(instance);
150
- }, []);
151
153
  return instance;
152
154
  }
153
155
  /**
154
156
  * 用法同{@link useEffect},但StrictMode下不会执行两次
155
157
  */
156
158
  export function useStrictEffect(effect, deps) {
157
- const prevDeps = useRef(void 0);
159
+ const hasRun = useRef(false);
160
+ const prevDeps = useRef(deps);
161
+ const prevCleanup = useRef(void 0);
158
162
  useEffect(() => {
159
- const isDepsChanged = prevDeps.current ? !arrayShallowEqual(prevDeps.current, deps) : true;
160
- if (isDepsChanged) {
163
+ const isDepsChanged = !arrayShallowEqual(prevDeps.current, deps);
164
+ if (!hasRun.current || isDepsChanged) {
165
+ prevCleanup.current?.();
166
+ prevCleanup.current = effect();
167
+ hasRun.current = true;
161
168
  prevDeps.current = deps;
162
- return effect();
163
169
  }
164
170
  });
171
+ useUnmounted(() => {
172
+ prevCleanup.current?.();
173
+ prevCleanup.current = void 0;
174
+ });
165
175
  }
166
176
  /**
167
177
  * 用法同{@link useEffect},但会排除首次渲染
@@ -185,7 +195,7 @@ export function useStrictMemo(factory, deps) {
185
195
  const isDepsChanged = prevDeps.current ? !arrayShallowEqual(prevDeps.current, deps) : true;
186
196
  if (isDepsChanged) {
187
197
  prevDeps.current = deps;
188
- return memoizedValue.current = factory();
198
+ memoizedValue.current = factory();
189
199
  }
190
200
  return memoizedValue.current;
191
201
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canlooks/can-ui",
3
- "version": "0.0.176",
3
+ "version": "0.0.177",
4
4
  "author": "C.CanLiang <canlooks@gmail.com>",
5
5
  "description": "My ui framework",
6
6
  "license": "MIT",