Skip to content

Commit 20ca73d

Browse files
committed
fix(provider): avoid stale styles when toggling dark/light theme
1 parent 73a27ab commit 20ca73d

1 file changed

Lines changed: 47 additions & 3 deletions

File tree

src/provider/useStyle/index.ts

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { TinyColor } from '@ctrl/tinycolor';
44
import { ConfigProvider as AntdConfigProvider, theme as antdTheme } from 'antd';
55
import type { GlobalToken } from 'antd/lib/theme/interface';
66
import type React from 'react';
7-
import { useContext } from 'react';
7+
import { useContext, useMemo, useRef } from 'react';
88
import { ProProvider } from '../index';
99
import type { ProTokenType } from '../typing/layoutToken';
1010

@@ -90,6 +90,24 @@ export const operationUnit = (token: ProAliasToken): CSSObject => ({
9090
},
9191
});
9292

93+
const hashString = (input: string): string => {
94+
let hash = 5381;
95+
for (let i = 0; i < input.length; i += 1) {
96+
hash = (hash * 33) ^ input.charCodeAt(i);
97+
}
98+
return (hash >>> 0).toString(36);
99+
};
100+
101+
const getProTokenKey = (token: ProAliasToken): string => {
102+
try {
103+
// ProProvider exposes finalToken instead of useCacheToken token,
104+
// so build a stable key from Pro token payload directly.
105+
return hashString(JSON.stringify(token));
106+
} catch {
107+
return '';
108+
}
109+
};
110+
93111
/**
94112
* 封装了一下 antd 的 useStyle
95113
* @param componentName {string} 组件的名字
@@ -117,11 +135,38 @@ export function useStyle(
117135
token.antCls = `.${getPrefixCls()}`;
118136

119137
// Register styles (side effect only in v2)
138+
// Keep path sensitive to both antd theme and Pro token updates.
139+
const proTokenKey = useMemo(() => {
140+
return getProTokenKey(token as ProAliasToken);
141+
}, [token]);
142+
143+
// Keep path monotonic across toggles to avoid style order issues
144+
// when switching dark -> light (back to an old key).
145+
const styleKey = [
146+
hashId,
147+
(theme as any).id,
148+
token.themeId,
149+
proTokenKey,
150+
]
151+
.filter(Boolean)
152+
.join('-');
153+
154+
const lastStyleKeyRef = useRef<string>('');
155+
const styleVersionRef = useRef(0);
156+
if (lastStyleKeyRef.current !== styleKey) {
157+
styleVersionRef.current += 1;
158+
lastStyleKeyRef.current = styleKey;
159+
}
160+
161+
const stylePath = [componentName, styleKey, styleVersionRef.current].filter(
162+
Boolean,
163+
);
164+
120165
useStyleRegister(
121166
{
122167
theme: theme as any,
123168
token,
124-
path: [componentName],
169+
path: stylePath,
125170
nonce: csp?.nonce,
126171
layer: {
127172
name: 'antd-pro',
@@ -130,7 +175,6 @@ export function useStyle(
130175
() => styleFn(token as ProAliasToken),
131176
);
132177

133-
// Return identity wrapper and hashId
134178
return {
135179
wrapSSR: (node: React.ReactElement) => node,
136180
hashId: hashed ? hashId : '',

0 commit comments

Comments
 (0)