Skip to content

Commit 31f9095

Browse files
JackWang032jialan
andauthored
refactor cookies (#294)
* feat: refactor cookies * test: add cookies test case * feat: optimize cookies doc * fix: optimize cookies code logic * feat: refactor cookies to hook * feat: improve cookies test case and update params name * feat: optimize cookies field change judge logic --------- Co-authored-by: jialan <[email protected]>
1 parent efb4c2e commit 31f9095

File tree

7 files changed

+341
-102
lines changed

7 files changed

+341
-102
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import { cleanup, renderHook } from '@testing-library/react';
2+
import '@testing-library/jest-dom/extend-expect';
3+
import useCookieListener from '../index';
4+
5+
jest.useFakeTimers({ advanceTimers: true });
6+
jest.spyOn(global, 'setInterval');
7+
jest.spyOn(global, 'setTimeout');
8+
9+
let cookies: { key: string; value: string }[] = [];
10+
11+
Object.defineProperty(window.document, 'cookie', {
12+
get() {
13+
return cookies.map((item) => `${item.key}=${item.value}`).join('; ');
14+
},
15+
set(value) {
16+
const arr = value.split('=');
17+
if (arr.length !== 2) return;
18+
const [key, val] = arr;
19+
const cookie = cookies.find((item) => item.key === key);
20+
cookie ? (cookie.value = val) : cookies.push({ key, value: val });
21+
},
22+
});
23+
24+
describe('test cookies', () => {
25+
beforeEach(() => {
26+
cleanup();
27+
cookies = [];
28+
});
29+
30+
// 新增的cookie项不会触发
31+
test('should not trigger when change cookie from an empty value', () => {
32+
const mockFieldsChanged = jest.fn();
33+
const timeout = 200;
34+
35+
renderHook(() =>
36+
useCookieListener(
37+
({ changedFields }) => mockFieldsChanged(changedFields),
38+
['dt_token'],
39+
{ timeout }
40+
)
41+
);
42+
43+
document.cookie = 'dt_token=token1';
44+
45+
return new Promise((resolve) => {
46+
setTimeout(() => {
47+
expect(mockFieldsChanged).not.toBeCalled();
48+
resolve(true);
49+
}, timeout);
50+
jest.runAllTimers();
51+
});
52+
});
53+
54+
test('should trigger when change cookie from an empty value with immediately option', () => {
55+
const mockFieldsChanged = jest.fn();
56+
const timeout = 200;
57+
58+
renderHook(() =>
59+
useCookieListener(
60+
({ changedFields }) => mockFieldsChanged(changedFields),
61+
['dt_token'],
62+
{ timeout, immediately: true }
63+
)
64+
);
65+
66+
document.cookie = 'dt_token=token1';
67+
68+
return new Promise((resolve) => {
69+
setTimeout(() => {
70+
expect(mockFieldsChanged).toBeCalled();
71+
expect(mockFieldsChanged.mock.calls[0][0]).toEqual([
72+
{ key: 'dt_token', value: 'token1' },
73+
]);
74+
resolve(true);
75+
}, timeout);
76+
jest.runAllTimers();
77+
});
78+
});
79+
80+
test('should trigger when change cookie from an exist value', () => {
81+
const mockFieldsChanged = jest.fn();
82+
const timeout = 200;
83+
84+
document.cookie = 'dt_token=token1';
85+
renderHook(() =>
86+
useCookieListener(
87+
({ changedFields }) => mockFieldsChanged(changedFields),
88+
['dt_token'],
89+
{ timeout }
90+
)
91+
);
92+
document.cookie = 'dt_token=token2';
93+
94+
return new Promise((resolve) => {
95+
setTimeout(() => {
96+
expect(mockFieldsChanged.mock.calls).toHaveLength(1);
97+
expect(mockFieldsChanged.mock.calls[0][0]).toEqual([
98+
{ key: 'dt_token', value: 'token2' },
99+
]);
100+
resolve(true);
101+
}, timeout);
102+
jest.runAllTimers();
103+
});
104+
});
105+
106+
test('should trigger with prevCookies and nextCookies when change cookie with empty watchfields', () => {
107+
const mockCookiesChanged = jest.fn();
108+
const timeout = 200;
109+
110+
renderHook(() => useCookieListener(mockCookiesChanged, [], { timeout }));
111+
112+
document.cookie = 'dt_token=token1';
113+
document.cookie = 'dt_userId=123';
114+
115+
return new Promise((resolve) => {
116+
setTimeout(() => {
117+
expect(mockCookiesChanged.mock.calls).toHaveLength(1);
118+
expect(mockCookiesChanged).toBeCalledWith({
119+
prevCookies: '',
120+
nextCookies: 'dt_token=token1; dt_userId=123',
121+
});
122+
resolve(true);
123+
}, timeout);
124+
jest.runAllTimers();
125+
});
126+
});
127+
128+
test('should compare cookie every timeout', () => {
129+
const mockCookiesChanged = jest.fn();
130+
const timeout = 100;
131+
132+
renderHook(() => useCookieListener(mockCookiesChanged, [], { timeout }));
133+
134+
document.cookie = 'dt_token=token1';
135+
document.cookie = 'dt_userId=123';
136+
137+
setTimeout(() => {
138+
document.cookie = 'dt_token=token2';
139+
document.cookie = 'dt_userId=1234';
140+
}, 1.5 * timeout);
141+
142+
return new Promise((resolve) => {
143+
setTimeout(() => {
144+
expect(mockCookiesChanged.mock.calls).toHaveLength(2);
145+
expect(mockCookiesChanged.mock.calls[0][0]).toEqual({
146+
prevCookies: '',
147+
nextCookies: 'dt_token=token1; dt_userId=123',
148+
});
149+
expect(mockCookiesChanged.mock.calls[1][0]).toEqual({
150+
prevCookies: 'dt_token=token1; dt_userId=123',
151+
nextCookies: 'dt_token=token2; dt_userId=1234',
152+
});
153+
resolve(true);
154+
}, 2 * timeout);
155+
jest.runAllTimers();
156+
});
157+
});
158+
});

src/cookies/demos/advanced.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import React, { useEffect } from 'react';
2+
import { useCookieListener } from 'dt-react-component';
3+
import utils from 'dt-react-component/utils';
4+
import { Button, message } from 'antd';
5+
6+
export default () => {
7+
useEffect(() => {
8+
utils.deleteCookie('dt_token');
9+
return () => utils.deleteAllCookies();
10+
}, []);
11+
12+
useCookieListener(
13+
({ changedFields }) => {
14+
console.log('cookie fields hasChanged', changedFields);
15+
if (changedFields?.length) {
16+
message.info(
17+
'以下Cookie字段发生变更:' +
18+
changedFields.map((field) => `${field.key} : ${field.value}`).join(',')
19+
);
20+
}
21+
},
22+
['dt_token'],
23+
{ immediately: true, timeout: 1000 }
24+
);
25+
26+
return (
27+
<div style={{ textAlign: 'center', paddingTop: 60 }}>
28+
<p>
29+
<Button
30+
onClick={() => {
31+
utils.setCookie('dt_token', `im_new_token_${Date.now()}`);
32+
}}
33+
>
34+
修改Cookie值
35+
</Button>
36+
</p>
37+
<p>监听页面 Cookie 信息变更</p>
38+
</div>
39+
);
40+
};

src/cookies/demos/basic.tsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import React, { useEffect } from 'react';
2+
import { useCookieListener } from 'dt-react-component';
3+
import utils from 'dt-react-component/utils';
4+
import { Button, message } from 'antd';
5+
6+
export default () => {
7+
useEffect(() => {
8+
utils.deleteCookie('dt_token');
9+
utils.deleteCookie('dt_userid');
10+
return () => utils.deleteAllCookies();
11+
}, []);
12+
13+
useCookieListener(
14+
({ changedFields }) => {
15+
console.log('cookie fields hasChanged', changedFields);
16+
if (changedFields?.length) {
17+
message.info(
18+
'以下Cookie字段发生变更:' +
19+
changedFields.map((field) => `${field.key} : ${field.value}`).join(',')
20+
);
21+
}
22+
},
23+
['dt_token']
24+
);
25+
26+
useCookieListener(({ prevCookies, nextCookies }) => {
27+
message.info(`监听到Cookie从 ${prevCookies} 变更为了 ${nextCookies} `);
28+
}, []);
29+
30+
return (
31+
<div style={{ textAlign: 'center', paddingTop: 60 }}>
32+
<p>
33+
<Button
34+
onClick={() => {
35+
utils.setCookie('dt_token', `im_new_token_${Date.now()}`);
36+
utils.setCookie('dt_userid', `im_new_userid_${Date.now()}`);
37+
}}
38+
>
39+
修改Cookie值
40+
</Button>
41+
</p>
42+
<p>监听页面 Cookie 信息变更</p>
43+
</div>
44+
);
45+
};

src/cookies/index.md

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,53 @@
11
---
2-
title: Cookies 监听 Cookie 变更
2+
title: useCookieListener 监听 Cookie 变更
33
group: 组件
44
toc: content
55
demo:
6-
cols: 2
6+
cols: 1
77
---
88

9-
# Cookies 监听 Cookie 变更
9+
# useCookieListener 监听 Cookie 变更
1010

1111
## 何时使用
1212

13-
监听页面 Cookie 信息变更
13+
- 监听某个 Cookie 值变更,变更后进行操作,如 token 变更进行登出
14+
- 在多个 tab 页下 Cookie 值变更,各 tab 页都需要及时同步时使用
15+
- 需要将该 hook 用于顶层组件中,如 Routes
1416

1517
## 示例
1618

17-
```jsx
18-
import React from 'react';
19-
import { Cookies } from 'dt-react-component';
20-
21-
export default () => {
22-
return (
23-
<>
24-
<p>监听页面 Cookie 信息变更</p>
25-
<Cookies
26-
// 当页面cookie如下字段的值发生变更时会触发页面刷新
27-
watchFields={['dt_token', 'dt_tenant_id', 'dt_user_id', 'project_id']}
28-
onFieldsChanged={() => {
29-
console.log('hasChanged');
30-
}}
31-
/>
32-
</>
33-
);
34-
};
35-
```
19+
<code src='./demos/basic.tsx' title='基本使用' iframe="true" description="当监听的Cookie字段为[]时,则Cookie有变化时就会触发,即监听整个Cookie的变化"></code>
20+
<code src='./demos/advanced.tsx' title='高级配置' iframe="true" description="通过immediately来配置是否Cookie字段新增时会触发变化,如有特殊要求,还可通过intervalTime来配置轮训比较的时间间隔"></code>
3621

3722
## API
3823

39-
### CookiesProps
24+
```tsx | pure
25+
useCookieListener(
26+
handler: (params: {prevCookies: string, nextCookies: string, changedFields?: Fields[]}) => void,
27+
watchFields: string[],
28+
options?: ICookieOptions
29+
)
30+
31+
```
32+
33+
### Params
34+
35+
| 参数 | 说明 | 类型 | 默认值 |
36+
| ----------- | ----------------------- | ---------------------------------------------------------------------------------------- | ------ |
37+
| handler | Cookie 变化时的处理函数 | `(params: {prevCookies: string, nextCookies: string, changedFields?: Fields[]}) => void` | - |
38+
| watchFields | 监听的具体 Cookie 字段 | `stirng[]` | - |
39+
| options | 配置项 | `CookieOptions` | - |
40+
41+
### CookieOptions
4042

41-
| 参数 | 说明 | 类型 | 默认值 |
42-
| --------------- | -------------------------------------------------- | ----------------------------- | ------ |
43-
| watchFields | 监听的一组 cookie | `string[]` | - |
44-
| onFieldsChanged | cookies 变更触发函数,fields 为当前 cookies 变更值 | `(fields: Fields[]) => void;` | - |
43+
| 参数 | 说明 | 类型 | 默认值 |
44+
| ----------- | --------------------------------------------------- | --------- | ------- |
45+
| immediately | Cookie 字段为新增字段时否会触发 handler,默认不触发 | `boolean` | `false` |
46+
| timeout | 监听轮训间隔时间,单位:毫秒 | `number` | `200` |
4547

4648
### Fields
4749

48-
| 参数 | 说明 | 类型 | 默认值 |
49-
| ----- | ---- | -------- | ------ |
50-
| key | - | `string` | - |
51-
| value | - | `string` | - |
50+
| 参数 | 说明 | 类型 | 默认值 |
51+
| ----- | --------- | -------- | ------ |
52+
| key | Cookie 键 | `string` | - |
53+
| value | Cookie 值 | `string` | - |

0 commit comments

Comments
 (0)