Skip to content

Commit 2b6a47e

Browse files
committed
feat: faq
1 parent 0c71244 commit 2b6a47e

File tree

2 files changed

+145
-1
lines changed

2 files changed

+145
-1
lines changed

src/faq/index.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
---
2+
title: FAQ
3+
order: 1
4+
toc: menu
5+
nav:
6+
title: FAQ
7+
path: /faq
8+
order: 4
9+
---
10+
11+
## 概览
12+
13+
用于记录一些项目中不常见的坑和解决办法。
14+
15+
## rxjs 和 hooks 使用陷阱
16+
17+
部分 UI 组件内部使用 rxjs 导致父组件回调函数中获取不到最新的状态
18+
如 InputSelect 组件内部在 useEffect 内部使用 rxjs 绑定事件,当选择某项的时候,调用 onValueChange 传递选项给父组件,如果父组件在 onValueChange 回调中拷贝之前的 state 进行修改,然后更新 state,可能在回调中获取不到最新的 state。
19+
20+
```ts
21+
import { useState } from 'react';
22+
import { times, cloneDeep, map } from 'lodash';
23+
import { headings } from '../../texts/utils';
24+
import { Stack } from '../../layouts/Stack';
25+
import { roundedEm, theme } from '../../core/theme';
26+
import { select } from '../../core/select';
27+
import { Input } from '../Input';
28+
import { InputSelect } from '../InputSelect';
29+
30+
export const InputSelects = () => {
31+
const [list, setList] = useState<Array<{ name: string }>>([]);
32+
33+
const enums = ['Apple', 'Orange', 'Banana'];
34+
35+
const handleChange = (val: string, index: number) => {
36+
const newVal = cloneDeep(list);
37+
newVal[index].name = val;
38+
setList(newVal);
39+
};
40+
41+
return (
42+
<>
43+
{map(list, (val, index) => {
44+
return (
45+
<Input>
46+
<InputSelect
47+
allowClear
48+
enum={enums}
49+
value={val}
50+
onValueChange={val => handleChange(val, index)}
51+
/>
52+
</Input>
53+
);
54+
})}
55+
</>
56+
);
57+
};
58+
```
59+
60+
原因:由于 InputSelect 组件内部的 rxjs 事件监听函数只在组件挂载后执行一次,而 onValueChange 回调依赖了外部状态,外部状态的更新导致回调函数更新,而 InputSelect 内部的 onValueChange 不是最新的函数,故出现了 state 渲染出错的问题。
61+
62+
解决:
63+
setState 采用回调函数来获取最新的 state。
64+
65+
```ts
66+
const handleChange = (val: string, index: number) => {
67+
setList(prev => {
68+
const newVal = cloneDeep(prev);
69+
newVal[index].name = val;
70+
return newVal;
71+
});
72+
};
73+
```
74+
75+
## 自定义 hooks 的使用陷阱
76+
77+
部分自定义 hooks 使用不当导致页面崩溃
78+
之前遇到过一次,开发环境页面正常,生产环境页面崩溃出现白屏,
79+
控制台报错指向如下链接:https://reactjs.org/docs/error-decoder.html/?invariant=300
80+
大概意思是 hooks 执行顺序不对,
81+
最终定位到出错的组件大概逻辑如下:
82+
83+
```ts
84+
import { useObservable } from '@reactorx/core';
85+
86+
const Example = () => {
87+
const { projectID, appName, env } = useInstance();
88+
const [data, , requesting$] = useTempDataOfRequest(
89+
listEconomyIndex,
90+
{
91+
projectID,
92+
appIDOrName: appName,
93+
env,
94+
dataType: time?.timeType as IDataReportTimeTypeTimeType,
95+
dataTime: time ? from : undefined,
96+
},
97+
[projectID, time],
98+
);
99+
100+
const requesting1 = useObservable(requesting$);
101+
102+
const [data2, , requesting$2] = useTempDataOfRequest(
103+
listEconomyIndex,
104+
{
105+
projectID,
106+
appIDOrName: appName,
107+
env,
108+
dataType: time?.timeType as IDataReportTimeTypeTimeType,
109+
dataTime: time ? from : undefined,
110+
},
111+
[projectID, time],
112+
);
113+
114+
const requesting2 = useObservable(requesting$2);
115+
116+
if (requesting1 || requesting2) {
117+
return <div>Loading</div>;
118+
}
119+
};
120+
```
121+
122+
以上组件出问题的 hook 是 useObservable,可以看到上面组件实现的功能是对两个请求的 loading 状态做了一个或运算,而 Webapck 在 prod 模式下启用编译压缩会将该或运算优化为如下代码:
123+
124+
```ts
125+
if (useObservable(requesting$) || useObservable(requesting$2)) {
126+
return <div>Loading</div>;
127+
}
128+
```
129+
130+
由于或运算的短路特点,就会出现两个 hook 可能只执行一个的情况,生产环境下该页面就出现崩溃的现象。
131+
132+
解决:
133+
134+
```ts
135+
const loading1 = useObservable(requesting$);
136+
if (loading1) {
137+
return <div>Loading</div>;
138+
}
139+
140+
const loading2 = useObservable(requesting$2);
141+
if (loading2) {
142+
return <div>Loading</div>;
143+
}
144+
```

src/framework/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ nav:
1010

1111
### 概览
1212

13-
webappkit 中的框架包含应用启动入口、路由、请求、表单、状态管理、持久化、权限、搜索、通知、时间格式化、表单验证、webworker 等,每个功能由单独的 npm 包提供,包名以@querycap 开头。
13+
webappkit 中的模块包含应用启动入口、路由、请求、表单、状态管理、持久化、权限、搜索、通知、时间格式化、表单验证、webworker 等,每个功能由单独的 npm 包提供,包名以@querycap 开头。

0 commit comments

Comments
 (0)