diff --git a/package.json b/package.json index 76b7150c..338f9bcd 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "@emotion/react": "^11.11.4", "@emotion/serialize": "^1.1.3", "@emotion/utils": "^1.2.1", + "rc-util": "^5.43.0", "use-merge-value": "^1.2.0" }, "devDependencies": { diff --git a/src/factories/createStyles/index.ts b/src/factories/createStyles/index.ts index bc178f47..2bc226a7 100644 --- a/src/factories/createStyles/index.ts +++ b/src/factories/createStyles/index.ts @@ -1,4 +1,6 @@ -import { Context, useContext, useMemo } from 'react'; +import useMemo from 'rc-util/lib/hooks/useMemo'; +import isEqual from 'rc-util/lib/isEqual'; +import { Context, useContext } from 'react'; import { Emotion, createCSS, serializeCSS } from '@/core'; import type { @@ -52,78 +54,86 @@ export const createStylesFactory = const responsiveMap = useMediaQueryMap(); - const styles = useMemo(() => { - let tempStyles: ReturnStyleToUse; - - // 函数场景 - if (styleOrGetStyle instanceof Function) { - const { stylish, appearance, isDarkMode, prefixCls, iconPrefixCls, ...token } = theme; - - // 创建响应式断点选择器的工具函数 - // @ts-ignore - const responsive: ResponsiveUtil = (styles) => - convertResponsiveStyleToString(styles, responsiveMap); - // 并赋予其相应的断点工具 - Object.assign(responsive, responsiveMap); - - tempStyles = styleOrGetStyle( - { - token, - stylish, - appearance, - isDarkMode, - prefixCls, - iconPrefixCls, - // 工具函数们 - cx, - css: serializeCSS, - responsive, - }, - props!, - ) as any; - } - // 没有函数时直接就是 object 或者 string - else { - tempStyles = styleOrGetStyle as any; - } - - if (typeof tempStyles === 'object') { - // 判断是否是用 reactCSS 生成的 - if (isReactCssResult(tempStyles)) { - // 如果是用 reactCss 生成的话,需要用 className 的 css 做一层转换 - tempStyles = toClassName(tempStyles) as any; - } else { - // 不是的话就是直接是 复合的 css object - tempStyles = Object.fromEntries( - Object.entries(tempStyles).map(([key, value]) => { - // 这里做两道转换: - // 1. 如果是用 babel 插件,则将样式的 label 设置为当前文件名 + key - // 2. 如果是 SerializedStyles ,将其用 cx 包一下转换成 className - - const label = usingBabel ? `${styleFileName}-${key}` : undefined; - - // 这里有可能是 { a : css` color:red ` } 也可能是 { b: { color:"blue" } } 这样的写法 - if (typeof value === 'object') { - if (usingBabel) { - return [key, toClassName(value, `label:${label}`) as any]; - } - - return [key, toClassName(value) as any]; - } - - // 这里只可能是 { c: cx(css`color:red`) } , 或者 d: 'abcd' 这样的写法 - return [key, value]; - }), + const styles = useMemo( + () => { + let tempStyles: ReturnStyleToUse; + + // 函数场景 + if (styleOrGetStyle instanceof Function) { + const { stylish, appearance, isDarkMode, prefixCls, iconPrefixCls, ...token } = theme; + + // 创建响应式断点选择器的工具函数 + // @ts-ignore + const responsive: ResponsiveUtil = (styles) => + convertResponsiveStyleToString(styles, responsiveMap); + // 并赋予其相应的断点工具 + Object.assign(responsive, responsiveMap); + + tempStyles = styleOrGetStyle( + { + token, + stylish, + appearance, + isDarkMode, + prefixCls, + iconPrefixCls, + // 工具函数们 + cx, + css: serializeCSS, + responsive, + }, + props!, ) as any; } - } + // 没有函数时直接就是 object 或者 string + else { + tempStyles = styleOrGetStyle as any; + } - return tempStyles; - }, [props, theme]); + if (typeof tempStyles === 'object') { + // 判断是否是用 reactCSS 生成的 + if (isReactCssResult(tempStyles)) { + // 如果是用 reactCss 生成的话,需要用 className 的 css 做一层转换 + tempStyles = toClassName(tempStyles) as any; + } else { + // 不是的话就是直接是 复合的 css object + tempStyles = Object.fromEntries( + Object.entries(tempStyles).map(([key, value]) => { + // 这里做两道转换: + // 1. 如果是用 babel 插件,则将样式的 label 设置为当前文件名 + key + // 2. 如果是 SerializedStyles ,将其用 cx 包一下转换成 className + + const label = usingBabel ? `${styleFileName}-${key}` : undefined; + + // 这里有可能是 { a : css` color:red ` } 也可能是 { b: { color:"blue" } } 这样的写法 + if (typeof value === 'object') { + if (usingBabel) { + return [key, toClassName(value, `label:${label}`) as any]; + } + + return [key, toClassName(value) as any]; + } + + // 这里只可能是 { c: cx(css`color:red`) } , 或者 d: 'abcd' 这样的写法 + return [key, value]; + }), + ) as any; + } + } - return useMemo(() => { - const { prefixCls, iconPrefixCls, ...res } = theme; - return { styles, cx, theme: res, prefixCls, iconPrefixCls }; - }, [styles, theme]); + return tempStyles; + }, + [props, theme], + (prev, next) => !isEqual(prev[0], next[0], true) || prev[1] !== next[1], + ); + + return useMemo( + () => { + const { prefixCls, iconPrefixCls, ...res } = theme; + return { styles, cx, theme: res, prefixCls, iconPrefixCls }; + }, + [styles, theme], + (prev, next) => !isEqual(prev[0], next[0], true) || prev[1] !== next[1], + ); }; };