React中如何避免子组件的循环渲染

在 React 开发中,有时候会遇到子组件循环渲染导致闪屏的问题,那如何避免呢?

以下代码实现了通过点击父表格某一行的按钮,弹出子表格的模态框以显示子表格及其数据(原代码是父表格有两个按钮,分别弹出不同的子表格,不是本节重点,所以代码没有写那一部分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import React, { useEffect } from 'react';
import { useImmer } from 'use-immer';
import { Table, Modal } from 'antd';
import axios from 'axios';
const ChildTable = (props) => {
const [state, setState] = useImmer({
childTableData: [],
childTableVisible: false,
});
useEffect(() => {
let responseData = [];
//通过传参获取到父表格点击的哪一行
modelId.modelId = props.row;
let getAllModel = axios({
//your request
}).then((response) => {
responseData = response.data.data;
setState((state) => {
state.childTableData = [...responseData];
if (props.row != 0) {
state.childTableVisible = true;
}
});
});
}, [props.row]);
// 子表格通过模态框呈现
const childTableColumns = [{}, {}];
return (
<Modal visible={state.verifyTableVisible} footer={null}>
<Table
columns={expandedColumns}
dataSource={state.verifyData}
pagination={false}
/>
</Modal>
);
};
const ParentTable = () => {
const [state, setState] = useImmer({
data: [],
rowId: 0,
});
//请求父表格数据
useEffect(() => {
let getParentTableData = axios({
//your request
}).then((response) => {
let responseData = response.data.data;
setState((state) => {
state.data = [...responseData];
});
});
}, []);
//ParentTable colums
const parentTableColumns = [{}, {}];
return (
<div className="container">
<Table
columns={parentTableColumns}
dataSource={state.data}
onRow={(record) => {
return {
onClick: () => {
setState((state) => {
state.rowId = record.id;
});
},
};
}}
/>
<ChildTable row={state.rowId} />
</div>
);
};
export default ParentTable;

上面的代码实际上定义了两个组件,父组件 ParentTable 和子组件 ChildTable,也可以分成两个文件来写。

不过一定不能把 ChildTable 函数写在 ParentTable 函数里面,如果这样的话,子表格请求数据,拿到数据之后如果写在固定数组里面,渲染不出数据,如果写在 setState 里面,又会循环渲染(因为更新 state 会触发渲染,渲染里面又有数据请求,就会又更新 state,死循环下去)。

所以网络请求不要放在渲染的方法里面,网络请求要么放用户触发的回调里面要么放初始化的地方(useEffect)。所以最后代码实现如上,子组件要用自己的 state,而不是父组件的,传递参数用 props。

最开始的需求是点击表格的某一行,弹出一个 popover,popover 里面有两个不同的按钮,点击相应的按钮会在父表格的这一行下面显示子表格。如果只有一个子表格比较容易,直接用 expandable 相关的 api 就可以,但是两个的话就比较麻烦了,试了条件渲染也不行,而且需求是不要展开的按钮,而 antd 子表格展开的动作就是由点击展开按钮 onExpand 触发的。后来想了一种思路是做 3 个表格,一个是只有父表格,一个是父表格加子表格 a,一个是父表格加子表格 b,根据按钮点击进行相应的渲染。最后觉得这种呈现方式不是很好,最终使用点击弹出模态框的呈现方式。

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2018-2020 Jee
  • Visitors: | Views:

如果您觉得此文章帮助到了您,请作者喝杯咖啡吧~

支付宝
微信