避免在反应组件中无限重新渲染
Posted
技术标签:
【中文标题】避免在反应组件中无限重新渲染【英文标题】:Avoiding infinite re-rendering in react component 【发布时间】:2022-01-21 07:04:46 【问题描述】:我有一个名为 threads 的 Supabase 数据库,有 5 个条目,我正在尝试为数据库中的每一列创建一个新的 React 组件,但我遇到了一些问题。
它给我的问题是它正在停止程序以防止无限循环,我认为这是因为在我的代码中,我每次渲染我知道的组件时都会更新我的 useState,但我'不知道如何解决这个问题。
Component.js:
import useState from "react";
import supabase from "../../utils/supabaseClient";
export default function Sidebar()
const [newThreads, setNewThreads] = useState([]);
// this is where I am kinda stuck
const threadList = [];
(async () =>
let data: threads, error = await supabase
.from('threads')
.select('thread_title');
threadList.push(threads); // how do I get the current index of the loop (and limit it to only get 5 entries?)
threadList.forEach(function (value)
console.log(value)
)
)();
setNewThreads(threadList);
return (
<div className="sidebar">
<div className="sidebar-widget">
<span className="widget-title">New Threads</span>
</div>
<div className="sidebar-widget">
<span className="widget-title">New Members</span>
(Object.entries(newThreads) || []).map(([key, value]) =>
return (
<div className="widget-cell">
<div className="widget-cell-image"/>
<div className="widget-cell-content">
<span className="widget-cell-title">value</span>
<div className="widget-cell-values">
<span className="widget-cell-by-user">by harley_swift,</span>
<span className="widget-cell-time">22:02</span>
</div>
</div>
</div>
);
)
</div>
</div>
)
任何关于解释的帮助将不胜感激!
【问题讨论】:
【参考方案1】:解决无限重新渲染问题的方法是使用useEffect
获取数据:
useEffect(() =>
// this is where I am kinda stuck
const threadList = [];
(async () =>
let
data: threads,
error
= await supabase
.from('threads')
.select('thread_title');
threadList.push(threads); // how do I get the current index of the loop (and limit it to only get 5 entries?)
threadList.forEach(function(value)
console.log(value)
)
)();
setNewThreads(threadList);
, []); // note the empty dependency list
空的依赖列表是你知道效果只会运行一次的方式之一。
要仅将 5 个项目添加到列表中,您可以对结果进行切片(或检查 supabase
是否具有这样做的内置方法):
threadList.push(threads.slice(0, 5));
最后,请注意状态更改是异步的,在您的情况下更是如此,因为您实际上是通过网络进行获取。
如果您想在newThreads
更新时收到通知,您可以使用另一个useEffect
,如下所示:
useEffect(() =>
if (newThreads)
console.warn(newThreads.length);
, [newThreads]);
if
语句并不是真正需要的,但为了完整性而添加
这也适用于当你想实际渲染newThreads
时,你需要使用条件渲染来做到这一点:
(Object.entries(newThreads) || []).map(([key, value]) =>
return (
<div className="widget-cell">
<div className="widget-cell-image" />
<div className="widget-cell-content">
<span className="widget-cell-title">value</span>
<div className="widget-cell-values">
<span className="widget-cell-by-user">by harley_swift,</span>
<span className="widget-cell-time">22:02</span>
</div>
</div>
</div>
);
) || <div>Loading...</div>
【讨论】:
绝对的救命稻草,谢谢! 我试过实际实现这段代码,看起来一切正常,但发生了一件事情:当我打印 newThreads 的长度时,它有时返回 0,有时返回 5,有时返回组件不要渲染(在 Object.entries 部分)。你知道为什么吗? (看起来它没有在初始渲染时渲染) @HarleySwift 这取决于您在哪里打印长度。状态变化不是同步的。如果您在错误的时间检查状态,您可能会看到与等待更长时间不同的情况。至于未渲染的组件,也可能与列表未按时填充有关。您可以在进行渲染之前添加检查以查看列表是否已准备好。我会更新我的答案 我只是做了一些实验,我硬编码了 arraylist 值,它工作得很好。您认为这与延迟/损坏的数据库检索有关吗?有没有办法我应该创建一个每 5 分钟更新一次的新列表,而不是每次都拉取它? @HarleySwift 是的,这绝对与必须先获取数据的延迟有关。我已经更新了我的答案。请在 *** 上提出一个新问题,以免我们从您的原始问题中脱离主题。以上是关于避免在反应组件中无限重新渲染的主要内容,如果未能解决你的问题,请参考以下文章
如何避免在反应功能组件中对“静态组件”进行不必要的重新渲染?
React 限制渲染次数以防止无限循环...重新渲染次数过多