feat: ConfigProvider support config warning level (#44809)

* test: add test case

* chore: use console.warn instead

* chore: support agg

* chore: fix lint
This commit is contained in:
二货爱吃白萝卜 2023-09-13 11:49:30 +08:00 committed by GitHub
parent a24b30c77e
commit b3428c678f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 86 additions and 20 deletions

View File

@ -1,9 +1,15 @@
import * as React from 'react';
import rcWarning, { resetWarned } from 'rc-util/lib/warning';
import rcWarning, { resetWarned as rcResetWarned } from 'rc-util/lib/warning';
export { resetWarned };
export function noop() {}
let deprecatedWarnList: Record<string, string[]> | null = null;
export function resetWarned() {
deprecatedWarnList = null;
rcResetWarned();
}
type Warning = (valid: boolean, component: string, message?: string) => void;
// eslint-disable-next-line import/no-mutable-exports
@ -32,7 +38,7 @@ type TypeWarning = (
) => void;
export interface WarningContextProps {
deprecated?: boolean;
strict?: boolean;
}
export const WarningContext = React.createContext<WarningContextProps>({});
@ -45,11 +51,33 @@ export const WarningContext = React.createContext<WarningContextProps>({});
export const devUseWarning: () => TypeWarning =
process.env.NODE_ENV !== 'production'
? () => {
const { deprecated } = React.useContext(WarningContext);
const { strict } = React.useContext(WarningContext);
const typeWarning: TypeWarning = (valid, component, type, message) => {
if (deprecated !== false || type !== 'deprecated') {
warning(valid, component, message);
if (!valid) {
if (strict === false && type === 'deprecated') {
const existWarning = deprecatedWarnList;
if (!deprecatedWarnList) {
deprecatedWarnList = {};
}
deprecatedWarnList[component] = deprecatedWarnList[component] || [];
if (!deprecatedWarnList[component].includes(message || '')) {
deprecatedWarnList[component].push(message || '');
}
// Warning for the first time
if (!existWarning) {
// eslint-disable-next-line no-console
console.warn(
'[antd] There exists deprecated usage in your code:',
deprecatedWarnList,
);
}
} else {
warning(valid, component, message);
}
}
};

View File

@ -139,7 +139,7 @@ const InternalAvatar: React.ForwardRefRenderFunction<HTMLSpanElement, AvatarProp
warning(
!(typeof icon === 'string' && icon.length > 2),
'Avatar',
'deprecated',
'breaking',
`\`icon\` is using ReactNode instead of string naming in v4. Please check \`${icon}\` at https://ant.design/components/icon`,
);
}

View File

@ -3,6 +3,7 @@ import { SmileOutlined } from '@ant-design/icons';
import type { ConfigConsumerProps, RenderEmptyHandler } from '..';
import ConfigProvider, { ConfigContext } from '..';
import { resetWarned } from '../../_util/warning';
import mountTest from '../../../tests/shared/mountTest';
import { fireEvent, render } from '../../../tests/utils';
import Button from '../../button';
@ -124,4 +125,17 @@ describe('ConfigProvider', () => {
expect(rendered).toBeTruthy();
expect(cacheRenderEmpty).toBeFalsy();
});
it('warning support filter level', () => {
resetWarned();
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
render(<ConfigProvider dropdownMatchSelectWidth warning={{ strict: false }} />);
expect(errSpy).not.toHaveBeenCalled();
expect(warnSpy).toHaveBeenCalled();
errSpy.mockRestore();
warnSpy.mockRestore();
});
});

View File

@ -0,0 +1,7 @@
## zh-CN
调整 warning 策略。
## en-US
Adjust warning strategy.

View File

@ -0,0 +1,14 @@
import React from 'react';
import { Alert, ConfigProvider, Input, Typography } from 'antd';
const App: React.FC = () => (
<>
<Typography.Title level={4}>Open single page to check the console</Typography.Title>
<ConfigProvider warning={{ strict: false }}>
<Alert closeText="deprecated" />
<Input.Group />
</ConfigProvider>
</>
);
export default App;

View File

@ -13,8 +13,8 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*YC4ERpGAddoAAA
This component provides a configuration to all React components underneath itself via the [context API](https://facebook.github.io/react/docs/context.html). In the render tree all components will have access to the provided config.
```tsx
import { ConfigProvider } from 'antd';
import React from 'react';
import { ConfigProvider } from 'antd';
// ...
const Demo: React.FC = () => (
@ -46,6 +46,7 @@ Some components use dynamic style to support wave effect. You can config `csp` p
<code src="./demo/wave.tsx">Custom Wave</code>
<code src="./demo/prefixCls.tsx" debug>prefixCls</code>
<code src="./demo/useConfig.tsx" debug>useConfig</code>
<code src="./demo/warning.tsx" debug>warning</code>
## API
@ -66,6 +67,7 @@ Some components use dynamic style to support wave effect. You can config `csp` p
| renderEmpty | Set empty content of components. Ref [Empty](/components/empty/) | function(componentName: string): ReactNode | - | |
| theme | Set theme, ref [Customize Theme](/docs/react/customize-theme) | - | - | 5.0.0 |
| virtual | Disable virtual scroll when set to `false` | boolean | - | 4.3.0 |
| warning | Config warning level, when `strict` is `false`, it will aggregate deprecated information into a single message | { strict: boolean } | - | 5.10.0 |
### ConfigProvider.config()

View File

@ -6,7 +6,7 @@ import useMemo from 'rc-util/lib/hooks/useMemo';
import { merge } from 'rc-util/lib/utils/set';
import type { Options } from 'scroll-into-view-if-needed';
import warning from '../_util/warning';
import warning, { WarningContext, type WarningContextProps } from '../_util/warning';
import type { RequiredMark } from '../form/Form';
import ValidateMessagesContext from '../form/validateMessagesContext';
import type { InputProps } from '../input';
@ -146,8 +146,7 @@ export interface ConfigProviderProps {
popupOverflow?: PopupOverflow;
theme?: ThemeConfig;
// TODO: wait for https://github.com/ant-design/ant-design/discussions/44551
// warning?: WarningContextProps;
warning?: WarningContextProps;
alert?: ComponentStyleConfig;
anchor?: ComponentStyleConfig;
@ -337,7 +336,7 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
colorPicker,
datePicker,
wave,
// warning: warningConfig,
warning: warningConfig,
} = props;
// =================================== Context ===================================
@ -427,7 +426,7 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
colorPicker,
datePicker,
wave,
// warning: warningConfig,
warning: warningConfig,
};
const config = {
@ -562,11 +561,11 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
}
// ================================== Warning ===================================
// if (memoedConfig.warning) {
// childNode = (
// <WarningContext.Provider value={memoedConfig.warning}>{childNode}</WarningContext.Provider>
// );
// }
if (memoedConfig.warning) {
childNode = (
<WarningContext.Provider value={memoedConfig.warning}>{childNode}</WarningContext.Provider>
);
}
// =================================== Render ===================================
if (componentDisabled !== undefined) {

View File

@ -14,8 +14,8 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*YC4ERpGAddoAAA
ConfigProvider 使用 React 的 [context](https://facebook.github.io/react/docs/context.html) 特性,只需在应用外围包裹一次即可全局生效。
```tsx
import { ConfigProvider } from 'antd';
import React from 'react';
import { ConfigProvider } from 'antd';
// ...
const Demo: React.FC = () => (
@ -46,7 +46,8 @@ export default Demo;
<code src="./demo/theme.tsx">主题</code>
<code src="./demo/wave.tsx">自定义波纹</code>
<code src="./demo/prefixCls.tsx" debug>前缀</code>
<code src="./demo/useConfig.tsx" debug>useConfig</code>
<code src="./demo/useConfig.tsx" debug>获取配置</code>
<code src="./demo/warning.tsx" debug>警告</code>
## API
@ -67,6 +68,7 @@ export default Demo;
| renderEmpty | 自定义组件空状态。参考 [空状态](/components/empty-cn) | function(componentName: string): ReactNode | - | |
| theme | 设置主题,参考 [定制主题](/docs/react/customize-theme-cn) | - | - | 5.0.0 |
| virtual | 设置 `false` 时关闭虚拟滚动 | boolean | - | 4.3.0 |
| warning | 设置警告等级,`strict` 为 `false` 时会将废弃相关信息聚合为单条信息 | { strict: boolean } | - | 5.10.0 |
### ConfigProvider.config()