【发布时间】:2020-03-17 15:20:27
【问题描述】:
我有一个应用程序请求 API 并有数千个结果。该 API 使用 limit offset 类型的分页。也就是说,我将限制(我想带来多少条记录)和偏移量(我想从哪条记录带来)作为参数传递。
问题是数据库每天有数千个结果。大约 150k 的结果。也就是说,每当我更新 React 的状态以添加新结果时,我都会遇到性能问题,因为 React 会重新渲染所有数据。
以下是部分代码。
async getHits(filters, resetContent = false) {
if(resetContent) {
this.setState({
isLoading: true
})
}
try {
const { data: { result } } = await API_CONFIG.get(`/hit${filters}`);
const formattedHits = formatHits(result);
let current;
if(resetContent) {
current = [...formattedHits];
} else {
current = [...this.state.hits, ...formattedHits]
}
this.setState(prevState => ({
hits: current,
currentOffset: resetContent ? 1 + DEFAULT_PAGINATION : prevState.currentOffset + DEFAULT_PAGINATION
}));
} catch (e) {
this.setState({
hits: [],
error: 'Houve um erro durante a requisição. Por favor, recarregue e tente novamente.'
});
} finally {
this.setState({
isLoading: false,
isLoadMoreLoading: false
})
}
}
例如,当我点击加载更多时,我将状态更改为将'isLoadMoreLoading'设置为true,因此我将文本从Carregar mais(葡萄牙文加载更多)更改为 Carregando(葡萄牙语加载)。这个过程需要很长时间,因为 React 会再次更新整个状态。
我在这里渲染内容:
const areEqual = (nextProps, prevProps) => {
if(nextProps === prevProps) {
return true
};
return false;
};
const TableResults = props => {
const { hits, isLoading, error } = props;
return (
<Table>
<thead>
<tr>
<TableHeader>Data</TableHeader>
<TableHeader>Parceiro</TableHeader>
<TableHeader>ID Arquivo</TableHeader>
<TableHeader>Nome do Cliente</TableHeader>
<TableHeader>Regra Afetada</TableHeader>
<TableHeader>Valor ME</TableHeader>
<TableHeader>Merchant Final</TableHeader>
<TableHeader>País Merchant Final</TableHeader>
<TableHeader>Gerador do Hit</TableHeader>
</tr>
</thead>
<tbody>
{isLoading && (
<tr>
<td className="content-not-allowed" colSpan={9}>
<Loader />
</td>
</tr>
)}
{!isLoading && error && (
<tr>
<td className="content-not-allowed not-found" colSpan={9}>
<span>{error}</span>
</td>
</tr>
)}
{!isLoading && !hits.length && !error && (
<tr>
<td className="content-not-allowed not-found" colSpan={9}>
<span>Sem resultados, revise sua busca.</span>
</td>
</tr>
)}
{!isLoading && !!hits.length && !error && (
hits.map(hit => (
<tr onClick={e => {
e.preventDefault();
props.history.push('/compliance/operations/'+hit.hit_id)
}} key={hit.hit_id}>
<td>{hit.created_at || '-'}</td>
<td>{hit.partner || '-'}</td>
<td>{hit.file_id || '-'}</td>
<td>{hit.cliente_nome || '-'}</td>
<td>{renderHitGenerator(hit.compliance_integration).description}</td>
<td>{hit.valorme || '-'}</td>
<td>{hit.merchant_nome_final || '-'}</td>
<td>{hit.merchant_pais_final || '-'}</td>
<td>{renderHitGenerator(hit.compliance_integration).name}</td>
</tr>
))
)}
</tbody>
</Table>
)
}
export default withRouter(React.memo(TableResults, areEqual));
我在互联网上查看了针对这么多数据优化结果,但没有找到令人满意的结果。
我怎样才能用这么多的数据更新 React 的状态并且仍然是一个执行者。
谢谢。
【问题讨论】:
-
看起来像以下任何一个(或多个)导致性能问题的问题: 1. 您确定要向 API 调用发送限制和偏移量吗? 2. 你设置了两次状态。在您的结果返回后一次,一次在
finally块中。您可以一口气完成。与error块相同。 3. 请检查您是否在重复组件中使用了key属性。这对于防止重新渲染数据很重要。 -
你在同一个组件内渲染数组组件吗?
-
感谢您的回复。 @Ashwin回应:1.是的,我在变量“过滤器”中发送限制。 2.我设置了2次状态,因为无论我是否设法带来API响应,我都必须删除加载程序。 3. 是的,我为每个渲染行传递 1 个密钥。 Burak 我用 React.memo 在另一个组件中渲染。我将把那段代码放在问题中。我的问题是不带数据。但我必须向我的状态添加越来越多的数据,而且它越来越重。
-
First Memo 没有用,因为 areEqual 使用 === 来检查对象实例是否相等。它总是错误的。
-
另一件事,您可以删除 isLoading 和错误检查。使它们与 hits.length 分开。主要显示表内的加载程序和错误使用表外的一些 div 或弹出微调器在视觉上看起来更快,甚至后端慢
标签: javascript reactjs