Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/alibaba/hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
crazylxr committed Oct 18, 2022
2 parents 1d0a501 + ae9cc20 commit 2405427
Show file tree
Hide file tree
Showing 12 changed files with 264 additions and 141 deletions.
54 changes: 27 additions & 27 deletions package.json 100644 → 100755
Expand Up @@ -26,50 +26,50 @@
"prepare": "husky install"
},
"devDependencies": {
"@ant-design/icons": "^4.7.0",
"@babel/cli": "^7.19.3",
"@babel/core": "^7.19.3",
"@ant-design/icons": "^4.6.2",
"@babel/cli": "^7.10.1",
"@babel/core": "^7.10.2",
"@commitlint/cli": "^17.1.2",
"@commitlint/config-conventional": "^17.1.0",
"@testing-library/react": "^10.4.9",
"@testing-library/react": "^10.0.4",
"@testing-library/react-hooks": "^8.0.1",
"@types/jest": "^27.5.2",
"@types/lodash.debounce": "^4.0.7",
"@types/lodash.isequal": "^4.5.6",
"@types/lodash.throttle": "^4.1.7",
"@types/react-router": "^5.1.19",
"@umijs/fabric": "^2.14.0",
"@types/jest": "^27.4.1",
"@types/lodash.debounce": "^4.0.6",
"@types/lodash.isequal": "^4.5.5",
"@types/lodash.throttle": "^4.1.6",
"@types/react-router": "^5.1.18",
"@umijs/fabric": "^2.1.0",
"@umijs/plugin-sass": "^1.1.1",
"antd": "^4.23.4",
"babel-loader": "^8.2.5",
"babel-plugin-import": "^1.13.5",
"babel-plugin-transform-async-to-promises": "^0.8.18",
"antd": "^4.3.3",
"babel-loader": "^8.1.0",
"babel-plugin-import": "^1.12.0",
"babel-plugin-transform-async-to-promises": "^0.8.15",
"coveralls": "^3.1.1",
"del": "^5.1.0",
"dumi": "^1.1.48",
"enzyme": "^3.11.0",
"eslint": "^7.32.0",
"eslint-plugin-react-hooks": "^4.6.0",
"fast-glob": "^3.2.12",
"fs-extra": "^10.1.0",
"enzyme": "^3.10.0",
"eslint": "^7.2.0",
"eslint-plugin-react-hooks": "^4.0.8",
"fast-glob": "^3.2.11",
"fs-extra": "^10.0.1",
"gray-matter": "^4.0.3",
"gulp": "^4.0.2",
"gulp-babel": "^8.0.0",
"gulp-typescript": "^6.0.0-alpha.1",
"husky": "^8.0.1",
"husky": "^8.0.0",
"jest": "^27.5.1",
"jest-fetch-mock": "^3.0.3",
"jest-localstorage-mock": "^2.4.22",
"jest-localstorage-mock": "^2.4.18",
"mockjs": "^1.1.0",
"prettier": "^2.7.1",
"prettier": "^2.0.5",
"pretty-quick": "^3.1.3",
"react": "^16.14.0",
"react-dom": "^16.14.0",
"react-drag-listview": "^0.1.9",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-drag-listview": "^0.1.6",
"react-shadow": "^19.0.3",
"react-test-renderer": "^16.14.0",
"react-test-renderer": "^16.13.1",
"rimraf": "^3.0.2",
"surge": "^0.21.7",
"surge": "^0.21.3",
"ts-jest": "^27.1.5",
"typescript": "^4.8.4",
"umi-request": "^1.2.18",
Expand Down
47 changes: 47 additions & 0 deletions packages/hooks/src/useHistoryTravel/__tests__/index.test.ts
Expand Up @@ -195,4 +195,51 @@ describe('useHistoryTravel', () => {
expect(hook.result.current.backLength).toEqual(0);
expect(hook.result.current.forwardLength).toEqual(0);
});

it('should work without max length', async () => {
const hook = renderHook(() => useHistoryTravel());
expect(hook.result.current.backLength).toEqual(0);
for (let i = 1; i <= 100; i++) {
act(() => {
hook.result.current.setValue(i);
});
}
expect(hook.result.current.forwardLength).toEqual(0);
expect(hook.result.current.backLength).toEqual(100);
expect(hook.result.current.value).toEqual(100);
});

it('should work with max length', async () => {
const hook = renderHook(() => useHistoryTravel(0, 10));
expect(hook.result.current.backLength).toEqual(0);
for (let i = 1; i <= 100; i++) {
act(() => {
hook.result.current.setValue(i);
});
}
expect(hook.result.current.forwardLength).toEqual(0);
expect(hook.result.current.backLength).toEqual(10);
expect(hook.result.current.value).toEqual(100);

act(() => {
hook.result.current.go(-5);
});
expect(hook.result.current.forwardLength).toEqual(5);
expect(hook.result.current.backLength).toEqual(5);
expect(hook.result.current.value).toEqual(95);

act(() => {
hook.result.current.go(5);
});
expect(hook.result.current.forwardLength).toEqual(0);
expect(hook.result.current.backLength).toEqual(10);
expect(hook.result.current.value).toEqual(100);

act(() => {
hook.result.current.go(-50);
});
expect(hook.result.current.forwardLength).toEqual(10);
expect(hook.result.current.backLength).toEqual(0);
expect(hook.result.current.value).toEqual(90);
});
});
33 changes: 33 additions & 0 deletions packages/hooks/src/useHistoryTravel/demo/demo3.tsx
@@ -0,0 +1,33 @@
/**
* title: Limit maximum history length
* desc: Limit the maximum number of history records to avoid excessive memory consumption.
*
* title.zh-CN: 限制历史记录最大长度
* desc.zh-CN: 限制最大历史记录数量,避免过度占用内存。
*/

import { useHistoryTravel } from 'ahooks';
import React from 'react';

export default () => {
const maxLength = 3;
const { value, setValue, backLength, forwardLength, back, forward } = useHistoryTravel<string>(
'',
maxLength,
);

return (
<div>
<div>maxLength: {maxLength}</div>
<div>backLength: {backLength}</div>
<div>forwardLength: {forwardLength}</div>
<input value={value || ''} onChange={(e) => setValue(e.target.value)} />
<button disabled={backLength <= 0} onClick={back} style={{ margin: '0 8px' }}>
back
</button>
<button disabled={forwardLength <= 0} onClick={forward}>
forward
</button>
</div>
);
};
13 changes: 9 additions & 4 deletions packages/hooks/src/useHistoryTravel/index.en-US.md
Expand Up @@ -17,6 +17,10 @@ A hook to manage state change history. It provides encapsulation methods to trav

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

### Limit maximum history length

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

## API

```typescript
Expand All @@ -28,14 +32,15 @@ const {
go,
back,
forward
} = useHistoryTravel<T>(initialValue?: T);
} = useHistoryTravel<T>(initialValue?: T, maxLength: number = 0 );
```

### Params

| Property | Description | Type | Default |
| ------------ | ---------------------- | ---- | ------- |
| initialValue | Optional initial value | `T` | - |
| Property | Description | Type | Default |
| ------------ | ------------------------------------------------------------------------------------------------------------------------- | -------- | ----------- |
| initialValue | Optional initial value | `T` | - |
| maxLength | Optional limit the maximum length of history records. If the maximum length is exceeded, the first record will be deleted | `number` | 0 unlimited |

### Result

Expand Down
12 changes: 10 additions & 2 deletions packages/hooks/src/useHistoryTravel/index.ts
Expand Up @@ -31,7 +31,7 @@ const split = <T>(step: number, targetArr: T[]) => {
};
};

export default function useHistoryTravel<T>(initialValue?: T) {
export default function useHistoryTravel<T>(initialValue?: T, maxLength: number = 0) {
const [history, setHistory] = useState<IData<T | undefined>>({
present: initialValue,
past: [],
Expand All @@ -54,10 +54,18 @@ export default function useHistoryTravel<T>(initialValue?: T) {
};

const updateValue = (val: T) => {
const _past = [...past, present];
const maxLengthNum = isNumber(maxLength) ? maxLength : Number(maxLength);
// maximum number of records exceeded
if (maxLengthNum > 0 && _past.length > maxLengthNum) {
//delete first
_past.splice(0, 1);
}

setHistory({
present: val,
future: [],
past: [...past, present],
past: _past,
});
};

Expand Down
13 changes: 9 additions & 4 deletions packages/hooks/src/useHistoryTravel/index.zh-CN.md
Expand Up @@ -17,6 +17,10 @@ nav:

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

### 限制历史记录最大长度

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

## API

```typescript
Expand All @@ -28,14 +32,15 @@ const {
go,
back,
forward
} = useHistoryTravel<T>(initialValue?: T);
} = useHistoryTravel<T>(initialValue?: T, maxLength: number = 0);
```

### Params

| 参数 | 说明 | 类型 | 默认值 |
| ------------ | ------------ | ----- | ------ |
| initialValue | 可选,初始值 | `any` | - |
| 参数 | 说明 | 类型 | 默认值 |
| ------------ | --------------------------------------------------------- | -------- | -------- |
| initialValue | 可选,初始值 | `any` | - |
| maxLength | 可选,限制历史记录最大长度,超过最大长度后将删除第一个记录 | `number` | 0 不限制 |

### Result

Expand Down
Expand Up @@ -39,4 +39,54 @@ describe('useRefreshOnWindowFocusPlugin', () => {
expect(hook.result.current.loading).toEqual(true);
hook.unmount();
});

it('fix: multiple unsubscriptions should not delete the last subscription listener ', async () => {
let hook1;
let hook2;
act(() => {
hook1 = setUp(request, {
refreshOnWindowFocus: true,
});
hook2 = setUp(request, {
refreshOnWindowFocus: true,
});
});

expect(hook1.result.current.loading).toEqual(true);
expect(hook2.result.current.loading).toEqual(true);

act(() => {
jest.advanceTimersByTime(1001);
});
await hook1.waitForNextUpdate();
expect(hook1.result.current.loading).toEqual(false);
expect(hook2.result.current.loading).toEqual(false);

act(() => {
fireEvent.focus(window);
});

expect(hook1.result.current.loading).toEqual(true);
expect(hook2.result.current.loading).toEqual(true);

act(() => {
jest.advanceTimersByTime(2000);
});

await hook1.waitForNextUpdate();

expect(hook1.result.current.loading).toEqual(false);
expect(hook2.result.current.loading).toEqual(false);

hook1.unmount();

act(() => {
jest.advanceTimersByTime(3000);
fireEvent.focus(window);
});

expect(hook1.result.current.loading).toEqual(false);
// hook2 should not unsubscribe
expect(hook2.result.current.loading).toEqual(true);
});
});
4 changes: 3 additions & 1 deletion packages/hooks/src/useRequest/src/utils/subscribeFocus.ts
Expand Up @@ -11,7 +11,9 @@ function subscribe(listener: Listener) {
listeners.push(listener);
return function unsubscribe() {
const index = listeners.indexOf(listener);
listeners.splice(index, 1);
if (index > -1) {
listeners.splice(index, 1);
}
};
}

Expand Down
2 changes: 1 addition & 1 deletion packages/hooks/src/useSetState/index.ts
Expand Up @@ -13,7 +13,7 @@ const useSetState = <S extends Record<string, any>>(
const setMergeState = useCallback((patch) => {
setState((prevState) => {
const newState = isFunction(patch) ? patch(prevState) : patch;
return newState ? Object.assign({}, prevState, newState) : prevState;
return newState ? { ...prevState, ...newState } : prevState;
});
}, []);

Expand Down
2 changes: 1 addition & 1 deletion packages/hooks/src/useTextSelection/demo/demo3.tsx
Expand Up @@ -17,7 +17,7 @@ export default () => {
<div ref={ref} style={{ border: '1px solid', padding: 20 }}>
<p>Please swipe your mouse to select any text on this paragraph.</p>
</div>
<p>Result:{JSON.stringify(selection)}</p>
<p style={{ wordWrap: 'break-word' }}>Result:{JSON.stringify(selection)}</p>
</div>
);
};
9 changes: 0 additions & 9 deletions packages/use-url-state/src/__tests__/router.test.tsx
@@ -1,14 +1,6 @@
import { act } from '@testing-library/react-hooks/dom';
import { setup } from '.';

const navigate = jest.fn();
jest.mock('react-router', () => {
return {
...jest.requireActual('react-router'),
useNavigate: () => navigate,
};
});

describe('React Router V6', () => {
it('useUrlState should be work', () => {
const res = setup(['/index']);
Expand All @@ -17,6 +9,5 @@ describe('React Router V6', () => {
});

expect(res.state).toMatchObject({ count: '1' });
expect(navigate).toBeCalledWith({ hash: '', search: 'count=1' }, { replace: false });
});
});

0 comments on commit 2405427

Please sign in to comment.