Skip to content

Commit 94f1215

Browse files
committed
✨ feat(useUpdateEffect): add useUpdateEffect hooks
1 parent 4ac526e commit 94f1215

File tree

6 files changed

+134
-2
lines changed

6 files changed

+134
-2
lines changed

src/index.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { useSize } from './useSize';
1010
import { useTimeout } from './useTimeout';
1111
import { useToggle } from './useToggle';
1212
import { useUnmount } from './useUnmount';
13+
import { useUpdateEffect } from './useUpdateEffect';
1314

1415
export {
1516
useBoolean,
@@ -22,7 +23,8 @@ export {
2223
useSize,
2324
useTimeout,
2425
useToggle,
25-
useUnmount
26+
useUnmount,
27+
useUpdateEffect
2628
};
2729

2830
export default {
@@ -36,5 +38,6 @@ export default {
3638
useSize,
3739
useTimeout,
3840
useToggle,
39-
useUnmount
41+
useUnmount,
42+
useUpdateEffect
4043
};
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* title: 基础用法
3+
*/
4+
import React, { useEffect, useState } from 'react';
5+
import { Button } from 'antd'
6+
import { useUpdateEffect } from '@pansy/react-hooks';
7+
8+
export default () => {
9+
const [count, setCount] = useState(0);
10+
const [effectCount, setEffectCount] = useState(0);
11+
const [updateEffectCount, setUpdateEffectCount] = useState(0);
12+
13+
useEffect(() => {
14+
setEffectCount((c) => c + 1);
15+
}, [count]);
16+
17+
useUpdateEffect(() => {
18+
setUpdateEffectCount((c) => c + 1);
19+
}, [count]);
20+
21+
return (
22+
<div>
23+
<p>effectCount: {effectCount}</p>
24+
<p>updateEffectCount: {updateEffectCount}</p>
25+
<p>
26+
<Button onClick={() => setCount((c) => c + 1)}>
27+
reRender
28+
</Button>
29+
</p>
30+
</div>
31+
);
32+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/* eslint-disable max-nested-callbacks */
2+
import { renderHook } from '@testing-library/react-hooks';
3+
import { useUpdateEffect } from '../index';
4+
5+
describe('useUpdateEffect', () => {
6+
it('should be defined', () => {
7+
expect(useUpdateEffect).toBeDefined();
8+
});
9+
10+
it('test on mounted', async () => {
11+
let mountedState = 1;
12+
const hook = renderHook(() =>
13+
useUpdateEffect(() => {
14+
mountedState = 2;
15+
}),
16+
);
17+
expect(mountedState).toEqual(1);
18+
hook.rerender();
19+
expect(mountedState).toEqual(2);
20+
});
21+
22+
it('test on optional', () => {
23+
let mountedState = 1;
24+
const hook = renderHook(() =>
25+
useUpdateEffect(() => {
26+
mountedState = 3;
27+
}, [mountedState]),
28+
);
29+
expect(mountedState).toEqual(1);
30+
hook.rerender();
31+
expect(mountedState).toEqual(1);
32+
mountedState = 2;
33+
hook.rerender();
34+
expect(mountedState).toEqual(3);
35+
});
36+
});

src/useUpdateEffect/index.md

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
title: useUpdateEffect
3+
nav:
4+
title: Hooks
5+
path: /hooks
6+
group:
7+
title: Effect
8+
path: /effect
9+
---
10+
11+
# useUpdateEffect
12+
13+
`useUpdateEffect` 用法等同于 `useEffect`,但是会忽略首次执行,只在依赖更新时执行。
14+
15+
## 代码演示
16+
17+
### 基础用法
18+
19+
<code src="./__demo__/demo01.tsx" />
20+
21+
## API
22+
23+
API 与 `React.useEffect` 完全一致。
24+
25+
```typescript
26+
useUpdateEffect(
27+
effect: React.EffectCallback,
28+
deps?: React.DependencyList,
29+
)
30+
```

src/useUpdateEffect/index.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { useEffect } from 'react';
2+
import { createUpdateEffect } from '../utils/createUpdateEffect';
3+
4+
/**
5+
* useUpdateEffect 用法等同于 useEffect,但是会忽略首次执行,只在依赖更新时执行
6+
*/
7+
export const useUpdateEffect = createUpdateEffect(useEffect);

src/utils/createUpdateEffect.ts

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { useRef } from 'react';
2+
import type { useEffect, useLayoutEffect } from 'react';
3+
4+
type effectHookType = typeof useEffect | typeof useLayoutEffect;
5+
6+
export const createUpdateEffect: (hook: effectHookType) => effectHookType =
7+
(hook) => (effect, deps) => {
8+
const isMounted = useRef(false);
9+
10+
// for react-refresh
11+
hook(() => {
12+
return () => {
13+
isMounted.current = false;
14+
};
15+
}, []);
16+
17+
hook(() => {
18+
if (!isMounted.current) {
19+
isMounted.current = true;
20+
} else {
21+
return effect();
22+
}
23+
}, deps);
24+
};

0 commit comments

Comments
 (0)