Skip to content

Commit

Permalink
feat: add new hook useModal
Browse files Browse the repository at this point in the history
  • Loading branch information
周星星同学 committed Aug 28, 2023
1 parent 5412bb7 commit 0ca0865
Show file tree
Hide file tree
Showing 9 changed files with 440 additions and 0 deletions.
1 change: 1 addition & 0 deletions config/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export const menus = [
'useScroll',
'useSize',
'useFocusWithin',
'useModal',
],
},
{
Expand Down
6 changes: 6 additions & 0 deletions packages/hooks/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ import useVirtualList from './useVirtualList';
import useWebSocket from './useWebSocket';
import useWhyDidYouUpdate from './useWhyDidYouUpdate';
import useMutationObserver from './useMutationObserver';
import { useModal, ModalProvider } from './useModal';
import type { ModalProps, ModalResult } from './useModal';

export {
useRequest,
Expand Down Expand Up @@ -156,4 +158,8 @@ export {
useRafTimeout,
useResetState,
useMutationObserver,
useModal,
ModalProvider,
};

export type { ModalProps, ModalResult };
67 changes: 67 additions & 0 deletions packages/hooks/src/useModal/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import { useModal, ModalProvider } from '../index'; // 请根据实际路径导入组件

// 模拟一个用于测试的组件
const TestComponent = () => {
const modal = useModal(TestModalComponent);

return (
<div>
<button onClick={() => modal.show()}>Show Modal</button>
</div>
);
};

const TestModalComponent = ({ visible, hide, destroy }) => {
return (
<div data-testid="modal" style={{ display: visible ? 'block' : 'none' }}>
<button data-testid="hide-button" onClick={hide}>
Hide Modal
</button>
<button data-testid="destroy-button" onClick={destroy}>
Destroy Modal
</button>
</div>
);
};

describe('useModal and ModalProvider', () => {
it('should show and hide modal', () => {
const { getByText, getByTestId } = render(
<ModalProvider>
<TestComponent />
</ModalProvider>,
);

const showModalButton = getByText('Show Modal');
fireEvent.click(showModalButton);

const modal = getByTestId('modal');
expect(modal).toBeVisible();

const hideButton = getByTestId('hide-button');
fireEvent.click(hideButton);

expect(modal).not.toBeVisible();
});

it('should destroy modal', () => {
const { getByText, getByTestId, queryByTestId } = render(
<ModalProvider>
<TestComponent />
</ModalProvider>,
);

const showModalButton = getByText('Show Modal');
fireEvent.click(showModalButton);

const modal = getByTestId('modal');
expect(modal).toBeVisible();

const destroyButton = getByTestId('destroy-button');
fireEvent.click(destroyButton);

expect(queryByTestId('modal')).toBeNull();
});
});
40 changes: 40 additions & 0 deletions packages/hooks/src/useModal/demo/MyModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { useEffect } from 'react';
import type { ModalProps } from 'ahooks';
import { Modal, message } from 'antd';

interface IData {
title?: string;
desc?: string;
}

interface IProps {
onOk: () => void;
onCancel?: () => void;
}

export default ({ visible, hide, destroy, data = {}, props }: ModalProps<IData, IProps>) => {
const { title = '新建', desc = 'Hello World!' } = data;
const { onOk, onCancel } = props;

useEffect(() => {
message.info('useEffect:' + title);
}, [title]);

return (
<Modal
title={title}
onOk={() => {
onOk?.();
hide();
}}
open={visible}
onCancel={() => {
onCancel?.();
hide();
}}
// afterClose={() => destroy()}
>
{desc}
</Modal>
);
};
11 changes: 11 additions & 0 deletions packages/hooks/src/useModal/demo/demo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ModalProvider } from 'ahooks';
import React from 'react';
import Demo1 from './demo1';

export default () => {
return (
<ModalProvider>
<Demo1 />
</ModalProvider>
);
};
36 changes: 36 additions & 0 deletions packages/hooks/src/useModal/demo/demo1.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import { useModal } from 'ahooks';
import { Button, Space, message } from 'antd';
import MyModal from './MyModal';

export default () => {
const { show, hide, destroy } = useModal(MyModal, {
onOk: () => {
message.success('ok');
},
onCancel: () => {
message.error('cancel');
},
});

return (
<>
{/* <MyModal /> */} {/* 无需再手动注册组件 */}
<Space>
<Button
onClick={() => {
show();
}}
>
新建
</Button>
<Button
onClick={() => show({ title: '编辑', desc: '你可以实时传入data,以供组件内部使用' })}
>
编辑
</Button>
<Button onClick={() => destroy()}>销毁</Button>
</Space>
</>
);
};
63 changes: 63 additions & 0 deletions packages/hooks/src/useModal/index.en-US.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
nav:
path: /hooks
---

# useModal

Easily use modal/drawer and other modal components in React:

- No need to manage internal state.
- Not tied to UI components.
- Internally uses Context to maintain context and does not lose global configuration.

## Code Example

### Basic Usage

<code src="./demo/demo.tsx" />

You need to wrap it with `ModalProvider` before using `useModal`.

```ts
import { ModalProvider } from "ahooks";

ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<ModalProvider>
<App />
</ModalProvider>
</React.StrictMode>
);
```

## API

```ts
import { useModal } from 'ahooks';
import type { ModalProps , ModalResult } from 'ahooks';

const Result:ModalResult = useModal<T,K>((Props:ModalProps<T,K>)=>{},props)
```

## Parameters

### Props

| Property | Description | Type | Default |
| -------- | -------------------------------------- | -------------------------------------- | ----------- |
| visible | Whether to show | `boolean` | `false` |
| hide | Hide | `() => void` | - |
| destroy | Destroy | `() => void` | - |
| data | Data passed in when Modal is opened | `T \| Record<string,any> \| undefined` | - |
| props | Props passed in when registering Modal | `K` | `undefined` |

> The difference between data and props is that data is passed in each time Modal is opened, and props is passed in when Modal is registered, and props will not change.
### Result

| Property | Description | Type | Default |
| -------- | ----------- | ------------------------------------------ | ------- |
| show | Show | `(data?: T \| Record<string,any>) => void` | - |
| hide | Hide | `() => void` | - |
| destroy | Destroy | `() => void` | - |
Loading

0 comments on commit 0ca0865

Please sign in to comment.