Skip to content

Commit

Permalink
feat(hooks): 完善 useMergeValue 文档及测试用例
Browse files Browse the repository at this point in the history
  • Loading branch information
nmsn committed Jul 17, 2023
1 parent 50cb4f7 commit 610bdf4
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export { default as useInView } from './useInView';
export { default as useLatest } from './useLatest';
export { default as useLoading } from './useLoading';
export { default as useMemoizedFn } from './useMemoizedFn';
export { default as useMergeValue } from './useMergeValue';
export { default as useMount } from './useMount';
export { default as useNoRenderState } from './useNoRenderState';
export { default as useOpen } from './useOpen';
Expand Down
51 changes: 51 additions & 0 deletions src/hooks/useMergeValue/demo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React, { useState } from 'react';

import { useMergeValue } from '@nmsn/utils';

const ControlledInput = ({
defaultValue,
value,
onChange,
}: {
defaultValue?: string;
value?: string;
onChange?: React.Dispatch<string>;
}) => {
const [curValue, setCurValue] = useMergeValue('', { defaultValue, value });

return (
<input
value={curValue}
onChange={e => {
setCurValue(e.target.value);
onChange?.(e.target.value);
}}
/>
);
};

const DEFAULT_VALUE = '1';
const VALUE = '2';

export default () => {
const [state1, setState1] = useState('');
const [state2, setState2] = useState(DEFAULT_VALUE);
const [state3, setState3] = useState(VALUE);
return (
<>
<p>不使用 value/defaultValue 的情况</p>
<ControlledInput onChange={setState1} />
<p>state: {state1}</p>
<p>---</p>
<p>使用 defaultValue 的情况</p>
<p>defaultValue: {DEFAULT_VALUE}</p>
<ControlledInput onChange={setState2} defaultValue={DEFAULT_VALUE} />
<p>state: {state2}</p>
<p>---</p>
<p>使用 value 的情况</p>
<p>value: {VALUE}</p>
<ControlledInput onChange={setState3} value={VALUE} />
<p>state: {state3}</p>
</>
);
};
36 changes: 36 additions & 0 deletions src/hooks/useMergeValue/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
title: useMergeValue
toc: false
---

# useMergeValue

帮助受控组件处理 value、defaultValue 的值

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

## API

```typescript
const [mergedValue, setState, stateValue] = useMergeValue<T>(
defaultStateValue: T,
props?: { defaultValue:?: T; value?: T }
)
: [T, React.Dispatch<React.SetStateAction<T>>, T];
```

### Params

| 参数 | 说明 | 类型 | 默认值 |
| ----------------- | ------------------ | ---- | ------ |
| defaultStateValue | `state` 默认值 | `T` | - |
| defaultValue | `props` 默认初始值 | `T` | - |
| value | `props`| `T` | - |

### Result

| 参数 | 说明 | 类型 | 默认值 |
| --------- | ---------------------------------------- | ----------------------------------------- | ------ |
| result[0] | 经过是否 `undefined` 判断的 `stateValue` | `T` | - |
| result[1] | 执行函数 | `React.Dispatch<React.SetStateAction<T>>` | - |
| result[2] | `stateValue` | `T` | - |
83 changes: 83 additions & 0 deletions src/hooks/useMergeValue/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { act, renderHook } from '@testing-library/react';

import useMergeValue from './';

const setUp = ({
defaultStateValue,
defaultValue,
value,
}: {
defaultStateValue?: string;
defaultValue?: string;
value?: string;
}) =>
renderHook(
({ defaultValue, value }: { defaultValue?: string; value?: string }) =>
useMergeValue(defaultStateValue, { defaultValue, value }),
{
initialProps: { defaultValue, value } as { defaultValue?: string; value?: string },
},
);

describe('useMergeValue', () => {
it('useMergeValue with defaultStateValue', async () => {
const { result } = setUp({ defaultStateValue: '1' });

expect(result.current?.[0]).toBe('1');
expect(result.current?.[2]).toBe('1');

act(() => {
result.current?.[1]('2');
});

expect(result.current?.[0]).toBe('2');
expect(result.current?.[2]).toBe('2');

act(() => {
result.current?.[1](undefined);
});

expect(result.current?.[0]).toBe(undefined);
expect(result.current?.[2]).toBe(undefined);
});

it('useMergeValue with defaultStateValue/defaultValue', async () => {
const { result } = setUp({ defaultStateValue: '1', defaultValue: '2' });

expect(result.current?.[0]).toBe('2');
expect(result.current?.[2]).toBe('2');

act(() => {
result.current?.[1]('3');
});

expect(result.current?.[0]).toBe('3');
expect(result.current?.[2]).toBe('3');
});

it('useMergeValue with defaultStateValue/value', async () => {
const { result, rerender } = setUp({ defaultStateValue: '1', value: '2' });

expect(result.current?.[0]).toBe('2');
expect(result.current?.[2]).toBe('2');

act(() => {
result.current?.[1]('3');
});

expect(result.current?.[0]).toBe('2');
expect(result.current?.[2]).toBe('3');

act(() => {
result.current?.[1](undefined);
});

expect(result.current?.[0]).toBe('2');
expect(result.current?.[2]).toBe(undefined);

rerender({ value: undefined });

expect(result.current?.[0]).toBe(undefined);
expect(result.current?.[2]).toBe(undefined);
});
});
2 changes: 2 additions & 0 deletions src/hooks/useMergeValue/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const useMergeValue = <T>(
const prevPropsValue = usePrevious(value);

const [stateValue, setStateValue] = useState<T>(
// 初始化值的逻辑
(() => {
if (!isUndefined(value)) {
return value;
Expand All @@ -31,6 +32,7 @@ const useMergeValue = <T>(
})(),
);

// 清除数据的逻辑
useEffect(() => {
if (firstRenderRef.current) {
firstRenderRef.current = false;
Expand Down

1 comment on commit 610bdf4

@vercel
Copy link

@vercel vercel bot commented on 610bdf4 Jul 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

utils – ./

nmsn-utils.vercel.app
utils-git-main-nmsn.vercel.app
utils-nmsn.vercel.app

Please sign in to comment.