仅在 useEffect 之后使用数据
Posted
技术标签:
【中文标题】仅在 useEffect 之后使用数据【英文标题】:using the data only AFTER useEffect 【发布时间】:2022-01-18 13:51:58 【问题描述】:我有一个反应组件(用 Typescript 编写),如下所示。
在这个组件中,我尝试读取包含数据的 excel,然后使用数据来渲染组件
由于在useEffect
运行之前没有读取数据,所以menuData被初始化为null
。
读取数据工作正常,menuData 没有错误。
但是,let meals = [...new Set(menuData.map((item: menuItem) => item.Meal))];
行抛出错误 TypeError: menuData is undefined
。我认为这是因为在 menuData 仍为 undefined
时(在 useEffect 运行之前)执行了此行。
如何克服这个错误?也就是说,let meals = [...new Set(menuData.map((item: menuItem) => item.Meal))];
let meals = [...new Set(menuData.map((item: menuItem) => item.Meal))];
useEffect 运行后如何运行?
我想将此行保留在 useEffect 之外,因为需要对 menuData 对象数组执行更多的数组函数(map、filter...等)。
export const CategoryItems = ( toggled : CategoryItemsProps) =>
const [menuData, setMenuData] = useState<menuData | undefined>(undefined);
/*Code to read the excel with menu items once the page is loaded.
The sheet will be read only once*/
useEffect(() =>
let url = "data.xlsx";
........
....
.....
setMenuData(XLSX.utils.sheet_to_json(worksheet, raw: true ));
, []);
let meals = [...new Set(menuData.map((item: menuItem) => item.Meal))];
return (
<div className=`category-items $toggled ? "theme-dark" : "theme-light"`>
.
.
.
//additional code to render the component based on the variable `meals`
.
.
.
</div>
</div>
);
;
【问题讨论】:
为什么不把状态初始化为一个空数组呢?const [menuData, setMenuData] = useState<menuData>([]);
我假设你的 useEffect 是异步的,所以你不能让它在它之后运行,因为这是将来会发生的事情。但是你可以做的是在 setMenuData 将触发的第二个渲染上运行它。你可以让 menuData 最初为空,但我个人喜欢提前返回 null 选项,如果它不处于要渲染的状态,为什么还要费心处理 JSX。所以在你的let meals
之前,只要做if (!menuData) return null;
,你当然可以用某种形式的加载指示器替换null
,这取决于你的useEffect 需要多长时间,如果这是你做的事情。
@PedroFeltrin 这行得通!如果您想将此作为答案。我会投票赞成。
@Keith 我不确定我是否完全理解您的建议。我应该在哪里添加if (!menuData) return null
?在useEffect
内?
@moys 不直接放在你的let meals
之前,基本上在使用useEffect
的时候,你一般会做多次渲染,通常不需要第一次渲染,因为你在等待来自的数据useEffect
..
【参考方案1】:
只需将您的状态初始化为一个空数组即可。
const [menuData, setMenuData] = useState<menuData>([]);
应该可以!
【讨论】:
【参考方案2】:如果数据尚未到来,我个人喜欢退出渲染阶段,因为useEffect
内的setState
无论如何都会导致另一个渲染。
if (!menuData) return null;
let meals = [...new Set(menuData.map((item: menuItem) => item.Meal))];
null
只是一种不渲染的简单方法..
我喜欢这种方式,如果您发现 useEffect
有时可能需要一些时间,而不是返回 null
,我们也许可以返回某种形式的加载指示器..
if (!menuData) return <div className="loading">Loading..</div>;
let meals = [...new Set(menuData.map((item: menuItem) => item.Meal))];
将数据初始化为空的东西是可行的,但是你有点松散了一些隐式状态,如果你渲染的结构更复杂,我发现提早退出更容易推理..
【讨论】:
感谢您的详细解释。出于我的目的,将数据初始化为空数组套装。但是,我接受您对详细解释的回答。谢谢。以上是关于仅在 useEffect 之后使用数据的主要内容,如果未能解决你的问题,请参考以下文章
React:如何使用功能性 usestate/useEffect 复制特定的组件类 setstate 回调示例?