Skip to content

Commit

Permalink
Merge branch 'master' into chore_merge_main
Browse files Browse the repository at this point in the history
  • Loading branch information
liuyib committed May 6, 2024
2 parents 7340355 + 6bec34c commit 1dae5f7
Show file tree
Hide file tree
Showing 22 changed files with 196 additions and 82 deletions.
2 changes: 1 addition & 1 deletion docs/guide/upgrade.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ The package.json will be:

Now, ahooks in your project is still v4, and ahooks4 is v5:

```tsx
```tsx | pure
import React from 'react';
import { useRequest } from 'ahooks'; // v3
import { useRequest } from 'ahooks4'; // v4
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/upgrade.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ $ bun add ahooks4@npm:ahooks@4

现在,你项目中的 ahooks 还是 v3 版本,ahooks4 是 v4 版本:

```tsx
```tsx | pure
import React from 'react';
import { useRequest } from 'ahooks'; // v3
import { useRequest } from 'ahooks4'; // v4
Expand Down
6 changes: 5 additions & 1 deletion packages/hooks/src/createUseStorageState/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ export function createUseStorageState(getStorage: () => Storage | undefined) {

const updateState = (value?: SetState<T>) => {
const currentState = isFunction(value) ? value(state) : value;
setState(currentState);

if (!listenStorageChange) {
setState(currentState);
}

try {
let newValue: string | null;
Expand Down Expand Up @@ -126,5 +129,6 @@ export function createUseStorageState(getStorage: () => Storage | undefined) {

return [state, useMemoizedFn(updateState)] as const;
}

return useStorageState;
}
21 changes: 21 additions & 0 deletions packages/hooks/src/useDynamicList/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ import useDynamicList from '../index';

describe('useDynamicList', () => {
const setUp = (props: any): any => renderHook(() => useDynamicList(props));
const warnSpy = jest.spyOn(console, 'error').mockImplementation(() => {});

afterEach(() => {
warnSpy.mockReset();
});

afterAll(() => {
warnSpy.mockRestore();
});

it('getKey should work', () => {
const hook = setUp([1, 2, 3]);
Expand Down Expand Up @@ -97,6 +106,18 @@ describe('useDynamicList', () => {
hook.result.current.remove(7);
});
expect(hook.result.current.list.length).toBe(7);

// batch remove
act(() => {
hook.result.current.batchRemove(1);
});
expect(warnSpy).toHaveBeenCalledWith(
'`indexes` parameter of `batchRemove` function expected to be an array, but got "number".',
);
act(() => {
hook.result.current.batchRemove([0, 1, 2]);
});
expect(hook.result.current.list.length).toBe(4);
});

it('same items should have different keys', () => {
Expand Down
29 changes: 22 additions & 7 deletions packages/hooks/src/useDynamicList/demo/demo1.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
*/

import React from 'react';
import { Input, Space } from 'antd';
import { Button, Input, Space } from 'antd';
import { MinusCircleOutlined, PlusCircleOutlined } from '@ant-design/icons';
import { useDynamicList } from 'ahooks';

export default () => {
const { list, remove, getKey, insert, replace } = useDynamicList(['David', 'Jack']);
const { list, remove, batchRemove, getKey, insert, replace } = useDynamicList(['David', 'Jack']);
const listIndexes = list.map((item, index) => index);

const Row = (index: number, item: any) => (
<Space key={getKey(index)}>
Expand All @@ -27,11 +28,25 @@ export default () => {
);

return (
<>
<Space style={{ marginBottom: 16 }} direction="vertical">
{list.map((ele, index) => Row(index, ele))}
<Space direction="vertical">
<Space direction="vertical">{list.map((ele, index) => Row(index, ele))}</Space>
<Space>
<Button
danger
disabled={list.length <= 1}
onClick={() => batchRemove(listIndexes.filter((index) => index % 2 === 0))}
>
Remove odd items
</Button>
<Button
danger
disabled={list.length <= 1}
onClick={() => batchRemove(listIndexes.filter((index) => index % 2 !== 0))}
>
Remove even items
</Button>
</Space>
<p>{JSON.stringify(list)}</p>
</>
<div>{JSON.stringify([list])}</div>
</Space>
);
};
33 changes: 33 additions & 0 deletions packages/hooks/src/useDynamicList/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useCallback, useRef, useState } from 'react';
import isDev from '../utils/isDev';

const useDynamicList = <T>(initialList: T[] = []) => {
const counterRef = useRef(-1);
Expand Down Expand Up @@ -77,6 +78,37 @@ const useDynamicList = <T>(initialList: T[] = []) => {
});
}, []);

const batchRemove = useCallback((indexes: number[]) => {
if (!Array.isArray(indexes)) {
if (isDev) {
console.error(
`\`indexes\` parameter of \`batchRemove\` function expected to be an array, but got "${typeof indexes}".`,
);
}
return;
}
if (!indexes.length) {
return;
}

setList((prevList) => {
const newKeyList: number[] = [];
const newList = prevList.filter((item, index) => {
const shouldKeep = !indexes.includes(index);

if (shouldKeep) {
newKeyList.push(getKey(index));
}

return shouldKeep;
});

keyList.current = newKeyList;

return newList;
});
}, []);

const move = useCallback((oldIndex: number, newIndex: number) => {
if (oldIndex === newIndex) {
return;
Expand Down Expand Up @@ -150,6 +182,7 @@ const useDynamicList = <T>(initialList: T[] = []) => {
merge,
replace,
remove,
batchRemove,
getKey,
getIndex,
move,
Expand Down
4 changes: 2 additions & 2 deletions packages/hooks/src/useFullscreen/demo/demo4.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/**
* title: Coexist with other full screen operations
* desc: The element's full screen may be modified by other scripts, don't worry, ahooks can work with them.
* description: The element's full screen may be modified by other scripts, don't worry, ahooks can work with them.
*
* title.zh-CN: 与其它全屏操作共存
* desc.zh-CN: 元素的全屏情况可能被其它脚本修改,不用担心,ahooks 可以与它们共存。
* description.zh-CN: 元素的全屏情况可能被其它脚本修改,不用担心,ahooks 可以与它们共存。
*/

import React, { useRef } from 'react';
Expand Down
4 changes: 2 additions & 2 deletions packages/hooks/src/useKeyPress/demo/demo8.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/**
* title: Get the trigger key
* desc: Multiple shortcuts are registered by a hook, each corresponding to a different logic.
* description: Multiple shortcuts are registered by a hook, each corresponding to a different logic.
*
* title.zh-CN: 获取触发的按键
* desc.zh-CN: 单个 hook 注册多个快捷键,每个快捷键对应不同逻辑。
* description.zh-CN: 单个 hook 注册多个快捷键,每个快捷键对应不同逻辑。
*/

import React, { useState } from 'react';
Expand Down
22 changes: 9 additions & 13 deletions packages/hooks/src/useLocalStorageState/demo/demo4.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
/**
* title: Sync state with localStorage
* desc: When the stored value changes, all `useLocalStorageState` with the same `key` will synchronize their states, including different tabs of the same browser (try to open two tabs of this page, clicking a button on one page will automatically update the "count" on the other page).
* description: When the stored value changes, all `useLocalStorageState` with the same `key` will synchronize their states, including different tabs of the same browser (try to open two tabs of this page, clicking a button on one page will automatically update the "count" on the other page).
*
* title.zh-CN: 将 state 与 localStorage 保持同步
* desc.zh-CN: 存储值变化时,所有 `key` 相同的 `useLocalStorageState` 会同步状态,包括同一浏览器不同 tab 之间(尝试打开两个此页面,点击其中一个页面的按钮,另一个页面的 count 会自动更新)
* description.zh-CN: 存储值变化时,所有 `key` 相同的 `useLocalStorageState` 会同步状态,包括同一浏览器不同 tab 之间(尝试打开两个此页面,点击其中一个页面的按钮,另一个页面的 count 会自动更新)
*/

import React from 'react';
import { Button, Space } from 'antd';
import { useLocalStorageState } from 'ahooks';

export default function () {
return (
<>
<Space direction="vertical">
<Counter />
<Counter />
</>
</Space>
);
}

Expand All @@ -24,15 +25,10 @@ function Counter() {
listenStorageChange: true,
});

const add = () => setCount(count! + 1);
const clear = () => setCount();

return (
<div style={{ marginBottom: '8px' }}>
<button style={{ marginRight: '8px' }} onClick={add}>
count: {count}
</button>
<button onClick={clear}>Clear</button>
</div>
<Space>
<Button onClick={() => setCount(count! + 1)}>count: {count}</Button>
<Button onClick={() => setCount()}>Clear</Button>
</Space>
);
}
5 changes: 1 addition & 4 deletions packages/hooks/src/useLocalStorageState/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ A Hook that store state into localStorage.
<code src="./demo/demo1.tsx"></code>
<code src="./demo/demo2.tsx"></code>
<code src="./demo/demo3.tsx"></code>

### Sync state with localStorage

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

## API

Expand Down
5 changes: 1 addition & 4 deletions packages/hooks/src/useLocalStorageState/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ demo:
<code src="./demo/demo1.tsx"></code>
<code src="./demo/demo2.tsx"></code>
<code src="./demo/demo3.tsx"></code>

### 将 state 与 localStorage 保持同步

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

## API

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/**
* title: Repeat last request
* desc: When the dependency array changes, use the previous parameters to make the request again.
* description: When the dependency array changes, use the previous parameters to make the request again.
*
* title.zh-CN: 重复上一次请求
* desc.zh-CN: 依赖数组变化时,使用上一次的参数重新发起请求。
* description.zh-CN: 依赖数组变化时,使用上一次的参数重新发起请求。
*/

import React, { useState } from 'react';
Expand Down
42 changes: 42 additions & 0 deletions packages/hooks/src/useSelections/__tests__/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { act, renderHook } from '@testing-library/react';
import { useState } from 'react';
import useSelections from '../index';
import type { Options } from '../index';

Expand Down Expand Up @@ -193,4 +194,45 @@ describe('useSelections', () => {
expect(result.current.selected).toEqual(_selected);
expect(result.current.isSelected(_selectedItem)).toBe(true);
});

it('clearAll should work correct', async () => {
const runCase = (data, newData, remainData) => {
const { result } = renderHook(() => {
const [list, setList] = useState(data);
const hook = useSelections(list, {
itemKey: 'id',
});

return { setList, hook };
});
const { setSelected, unSelectAll, clearAll } = result.current.hook;

act(() => {
setSelected(data);
});
expect(result.current.hook.selected).toEqual(data);
expect(result.current.hook.allSelected).toBe(true);

act(() => {
result.current.setList(newData);
});
expect(result.current.hook.allSelected).toBe(false);

act(() => {
unSelectAll();
});
expect(result.current.hook.selected).toEqual(remainData);

act(() => {
clearAll();
});
expect(result.current.hook.selected).toEqual([]);
expect(result.current.hook.allSelected).toEqual(false);
expect(result.current.hook.noneSelected).toBe(true);
expect(result.current.hook.partiallySelected).toBe(false);
};

runCase(_data, [3, 4, 5], [1, 2]);
runCase(_dataObj, [{ id: 3 }, { id: 4 }, { id: 5 }], [{ id: 1 }, { id: 2 }]);
});
});
4 changes: 2 additions & 2 deletions packages/hooks/src/useSelections/demo/demo2.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/**
* title: Object array
* desc: When array items are object, you need to specify the field name for the unique key.
* description: When array items are object, you need to specify the field name for the unique key.
*
* title.zh-CN: 对象数组
* desc.zh-CN: 数组项是对象时,需要指定唯一 key 的字段名称。
* description.zh-CN: 数组项是对象时,需要指定唯一 key 的字段名称。
*/

import { Checkbox, Col, Row } from 'antd';
Expand Down
4 changes: 2 additions & 2 deletions packages/hooks/src/useSelections/demo/demo3.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/**
* title: Pagination
* desc: Load data with pagination and enable cross-page selection.
* description: Load data with pagination and enable cross-page selection.
*
* title.zh-CN: 分页多选
* desc.zh-CN: 分页加载数据,并跨页选择。
* description.zh-CN: 分页加载数据,并跨页选择。
*/

import { Checkbox, Divider, Pagination, Spin } from 'antd';
Expand Down
Loading

0 comments on commit 1dae5f7

Please sign in to comment.