Browse Source
* use promise for getInstance * passing hooks * hooks support * move hooks out of fiel * adjust style * update snapshot * fix test & add test case * update hooks test * fix style lint * update doc * update demo desc & eslitn rules * fix lint * docs add faq * fix lesspull/21284/head
二货机器人
5 years ago
committed by
GitHub
13 changed files with 454 additions and 86 deletions
@ -0,0 +1,53 @@ |
|||
/* eslint-disable jsx-a11y/control-has-associated-label */ |
|||
import React from 'react'; |
|||
import { mount } from 'enzyme'; |
|||
import notification from '..'; |
|||
import ConfigProvider from '../../config-provider'; |
|||
|
|||
describe('notification.hooks', () => { |
|||
beforeAll(() => { |
|||
jest.useFakeTimers(); |
|||
}); |
|||
|
|||
afterAll(() => { |
|||
jest.useRealTimers(); |
|||
}); |
|||
|
|||
afterEach(() => { |
|||
notification.destroy(); |
|||
}); |
|||
|
|||
it('should work', () => { |
|||
const Context = React.createContext('light'); |
|||
|
|||
const Demo = () => { |
|||
const [api, holder] = notification.useNotification(); |
|||
|
|||
return ( |
|||
<ConfigProvider prefixCls="my-test"> |
|||
<Context.Provider value="bamboo"> |
|||
<button |
|||
type="button" |
|||
onClick={() => { |
|||
api.open({ |
|||
description: ( |
|||
<Context.Consumer> |
|||
{name => <span className="hook-test-result">{name}</span>} |
|||
</Context.Consumer> |
|||
), |
|||
duration: 0, |
|||
}); |
|||
}} |
|||
/> |
|||
{holder} |
|||
</Context.Provider> |
|||
</ConfigProvider> |
|||
); |
|||
}; |
|||
|
|||
const wrapper = mount(<Demo />); |
|||
wrapper.find('button').simulate('click'); |
|||
expect(document.querySelectorAll('.my-test-notification-notice').length).toBe(1); |
|||
expect(document.querySelector('.hook-test-result').innerHTML).toEqual('bamboo'); |
|||
}); |
|||
}); |
@ -0,0 +1,63 @@ |
|||
--- |
|||
order: 8 |
|||
title: |
|||
zh-CN: 通过 Hooks 获取上下文 |
|||
en-US: Get context with hooks |
|||
--- |
|||
|
|||
## zh-CN |
|||
|
|||
通过 `notification.useNotification` 创建支持读取 context 的 `contextHolder`。 |
|||
|
|||
## en-US |
|||
|
|||
Use `notification.useNotification` to get `contextHolder` with context accessible issue. |
|||
|
|||
```jsx |
|||
import { Button, notification, Divider } from 'antd'; |
|||
import { |
|||
RadiusUpleftOutlined, |
|||
RadiusUprightOutlined, |
|||
RadiusBottomleftOutlined, |
|||
RadiusBottomrightOutlined, |
|||
} from '@ant-design/icons'; |
|||
|
|||
const Context = React.createContext({ name: 'Default' }); |
|||
|
|||
const Demo = () => { |
|||
const [api, contextHolder] = notification.useNotification(); |
|||
|
|||
const openNotification = placement => { |
|||
api.info({ |
|||
message: `Notification ${placement}`, |
|||
description: <Context.Consumer>{({ name }) => `Hello, ${name}!`}</Context.Consumer>, |
|||
placement, |
|||
}); |
|||
}; |
|||
|
|||
return ( |
|||
<Context.Provider value={{ name: 'Ant Design' }}> |
|||
{contextHolder} |
|||
<Button type="primary" onClick={() => openNotification('topLeft')}> |
|||
<RadiusUpleftOutlined /> |
|||
topLeft |
|||
</Button> |
|||
<Button type="primary" onClick={() => openNotification('topRight')}> |
|||
<RadiusUprightOutlined /> |
|||
topRight |
|||
</Button> |
|||
<Divider /> |
|||
<Button type="primary" onClick={() => openNotification('bottomLeft')}> |
|||
<RadiusBottomleftOutlined /> |
|||
bottomLeft |
|||
</Button> |
|||
<Button type="primary" onClick={() => openNotification('bottomRight')}> |
|||
<RadiusBottomrightOutlined /> |
|||
bottomRight |
|||
</Button> |
|||
</Context.Provider> |
|||
); |
|||
}; |
|||
|
|||
ReactDOM.render(<Demo />, mountNode); |
|||
``` |
@ -0,0 +1,72 @@ |
|||
import * as React from 'react'; |
|||
import useRCNotification from 'rc-notification/lib/useNotification'; |
|||
import { |
|||
NotificationInstance as RCNotificationInstance, |
|||
NoticeContent as RCNoticeContent, |
|||
HolderReadyCallback as RCHolderReadyCallback, |
|||
} from 'rc-notification/lib/Notification'; |
|||
import { ConfigConsumer, ConfigConsumerProps } from '../../config-provider'; |
|||
import { NotificationInstance, ArgsProps } from '..'; |
|||
|
|||
export default function createUseNotification( |
|||
getNotificationInstance: ( |
|||
args: ArgsProps, |
|||
callback: (info: { prefixCls: string; instance: RCNotificationInstance }) => void, |
|||
) => void, |
|||
getRCNoticeProps: (args: ArgsProps, prefixCls: string) => RCNoticeContent, |
|||
) { |
|||
const useNotification = (): [NotificationInstance, React.ReactElement] => { |
|||
// We can only get content by render
|
|||
let getPrefixCls: ConfigConsumerProps['getPrefixCls']; |
|||
|
|||
// We create a proxy to handle delay created instance
|
|||
let innerInstance: RCNotificationInstance | null = null; |
|||
const proxy = { |
|||
add: (noticeProps: RCNoticeContent, holderCallback?: RCHolderReadyCallback) => { |
|||
innerInstance?.component.add(noticeProps, holderCallback); |
|||
}, |
|||
} as any; |
|||
|
|||
const [hookNotify, holder] = useRCNotification(proxy); |
|||
|
|||
function notify(args: ArgsProps) { |
|||
const { prefixCls: customizePrefixCls } = args; |
|||
const mergedPrefixCls = getPrefixCls('notification', customizePrefixCls); |
|||
|
|||
getNotificationInstance( |
|||
{ |
|||
...args, |
|||
prefixCls: mergedPrefixCls, |
|||
}, |
|||
({ prefixCls, instance }) => { |
|||
innerInstance = instance; |
|||
hookNotify(getRCNoticeProps(args, prefixCls)); |
|||
}, |
|||
); |
|||
} |
|||
|
|||
// Fill functions
|
|||
const hookAPI: any = { |
|||
open: notify, |
|||
}; |
|||
['success', 'info', 'warning', 'error'].forEach(type => { |
|||
hookAPI[type] = (args: ArgsProps) => |
|||
hookAPI.open({ |
|||
...args, |
|||
type, |
|||
}); |
|||
}); |
|||
|
|||
return [ |
|||
hookAPI, |
|||
<ConfigConsumer key="holder"> |
|||
{(context: ConfigConsumerProps) => { |
|||
({ getPrefixCls } = context); |
|||
return holder; |
|||
}} |
|||
</ConfigConsumer>, |
|||
]; |
|||
}; |
|||
|
|||
return useNotification; |
|||
} |
Loading…
Reference in new issue