Skip to content

Commit 61b7c90

Browse files
committed
feat: ✨ add useLogger
1 parent eb700b9 commit 61b7c90

File tree

8 files changed

+15263
-14006
lines changed

8 files changed

+15263
-14006
lines changed

config/hooks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,6 @@ export const menus = [
116116
},
117117
{
118118
title: 'Dev',
119-
children: ['useTrackedEffect', 'useWhyDidYouUpdate'],
119+
children: ['useTrackedEffect', 'useWhyDidYouUpdate', 'useLogger'],
120120
},
121121
];

packages/hooks/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ import useVirtualList from './useVirtualList';
7575
import useWebSocket from './useWebSocket';
7676
import useWhyDidYouUpdate from './useWhyDidYouUpdate';
7777
import useMutationObserver from './useMutationObserver';
78+
import useLogger from './useLogger';
7879

7980
export {
8081
useRequest,
@@ -156,4 +157,5 @@ export {
156157
useRafTimeout,
157158
useResetState,
158159
useMutationObserver,
160+
useLogger,
159161
};
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { renderHook, act } from '@testing-library/react';
2+
import useLogger from '../index';
3+
4+
describe('useLogger', () => {
5+
// test ueslogger in every lifecycle of component
6+
// mounted unmounted updated rerendered
7+
it('should be defined', () => {
8+
expect(useLogger).toBeDefined();
9+
});
10+
it('should log mounted', () => {
11+
const spy = jest.spyOn(console, 'log');
12+
const { unmount } = renderHook(() => useLogger('Demo', { title: 'Hello World', size: 24 }, 0));
13+
expect(spy).toBeCalledWith('Demo mounted', { size: 24, title: 'Hello World' }, 0);
14+
act(() => {
15+
unmount();
16+
});
17+
});
18+
it('should log updated', () => {
19+
const spy = jest.spyOn(console, 'log');
20+
const { rerender } = renderHook(() => useLogger('Demo', { title: 'Hello World', size: 24 }, 0));
21+
act(() => {
22+
rerender();
23+
});
24+
expect(spy).toBeCalledWith('Demo updated', { size: 24, title: 'Hello World' }, 0);
25+
});
26+
it('should log unmounted', () => {
27+
const spy = jest.spyOn(console, 'log');
28+
const { unmount } = renderHook(() => useLogger('Demo', { title: 'Hello World', size: 24 }, 0));
29+
act(() => {
30+
unmount();
31+
});
32+
expect(spy).toBeCalledWith('Demo mounted', { size: 24, title: 'Hello World' }, 0);
33+
expect(spy).toBeCalledWith('Demo unmounted');
34+
});
35+
});
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* title: Basic usage
3+
* desc: A hook that console logs parameters as component transitions through lifecycles.
4+
*
5+
* title.zh-CN: 基础用法
6+
* desc.zh-CN: 一个在控制台中输出组件生命周期内日志的Hook。
7+
*/
8+
9+
import React, { useState } from 'react';
10+
import { useLogger, useCounter } from 'ahooks';
11+
12+
const Demo = (props) => {
13+
const [state, { inc }] = useCounter(0);
14+
15+
useLogger('Demo', props, state);
16+
17+
return (
18+
<>
19+
<p style={{ fontSize: props.size }}>{props.title}</p>
20+
<button onClick={() => inc()}>Update state ({state})</button>
21+
</>
22+
);
23+
};
24+
25+
export default () => {
26+
const [outerCount, setOutCounter] = useState(24); // default font size
27+
28+
return (
29+
<>
30+
<Demo title="Hello World" size={outerCount} />
31+
<button onClick={() => setOutCounter((c) => c + 1)}>Increase font size ({outerCount})</button>
32+
</>
33+
);
34+
};
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
nav:
3+
path: /hooks
4+
---
5+
6+
# useLogger
7+
8+
A hook that console logs parameters as component transitions through lifecycles.
9+
10+
## Examples
11+
12+
### Default usage
13+
14+
<code src="./demo/demo1.tsx" />
15+
16+
## API
17+
18+
```typescript
19+
useLogger(componentName: string, ...rest);
20+
```
21+
22+
### Params
23+
24+
| Property | Description | Type | Default |
25+
| ------------- | ------------------ | -------- | ------- |
26+
| componentName | component name. | `string` | - |
27+
| ...rest | parameters to log. | `string` | - |

packages/hooks/src/useLogger/index.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import type { EffectCallback } from 'react';
2+
import { useEffect, useRef } from 'react';
3+
4+
const useEffectOnce = (effect: EffectCallback) => {
5+
useEffect(effect, []);
6+
};
7+
export function useFirstMountState(): boolean {
8+
const isFirst = useRef(true);
9+
10+
if (isFirst.current) {
11+
isFirst.current = false;
12+
13+
return true;
14+
}
15+
16+
return isFirst.current;
17+
}
18+
19+
const useUpdateEffect: typeof useEffect = (effect, deps) => {
20+
const isFirstMount = useFirstMountState();
21+
22+
useEffect(() => {
23+
if (!isFirstMount) {
24+
return effect();
25+
}
26+
}, deps);
27+
};
28+
29+
const useLogger = (componentName: string, ...rest) => {
30+
useEffectOnce(() => {
31+
console.log(`${componentName} mounted`, ...rest);
32+
return () => console.log(`${componentName} unmounted`);
33+
});
34+
35+
useUpdateEffect(() => {
36+
console.log(`${componentName} updated`, ...rest);
37+
});
38+
};
39+
40+
export default useLogger;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
nav:
3+
path: /hooks
4+
---
5+
6+
# useLogger
7+
8+
一个在控制台中输出组件生命周期内日志的Hook。
9+
10+
## 代码演示
11+
12+
### 基础用法
13+
14+
<code src="./demo/demo1.tsx" />
15+
16+
## API
17+
18+
```typescript
19+
useLogger(componentName: string, ...rest);
20+
```
21+
22+
### Params
23+
24+
| 参数 || 类型 | 默认值 |
25+
| ------------- | ---------- | -------- | ------ |
26+
| componentName | 组件名称 | `string` | - |
27+
| ...rest | 输出的日志 | `string` | - |

0 commit comments

Comments
 (0)