如何在react组件函数内部的useEffect中观察全局Set变量的变化



我有一个页面,其中有Listings。用户可以检查此列表中的项目。

每当用户检查某个东西时,它就会被添加到全局声明的集合中(每个项目的唯一ID都被添加到该集合中(。此集合中的ID需要由一个单独的组件(让我们称之为PROCESS_COMPONENT(访问,该组件处理ID存在于该集合中的特定Listings。

我的Listings代码大致如下:

import React from "react";
import { CheckBox, PROCESS_COMPONENT } from "./Process.jsx";
const ListItem = ({lItem}) => {
return (
<>
//name,image,info,etc.
<CheckBox lId={lItem.id}/>
</>
)
};
function Listings() {
// some declarations blah blah..
return (
<>
<PROCESS_COMPONENT /> // Its a sticky window that shows up on top of the Listings.
//..some divs and headings
dataArray.map(item => { return <ListItem lItem={item} /> }) // Generates the list also containing the checkboxes
</>
)
}

并且CheckboxPROCESS_COMPONENT功能存在于单独的文件(Process.jsx(中。

它看起来大致像:

import React, { useEffect, useState } from "react";
let ProcessSet = new Set(); // The globally declared set.
const CheckBox = ({lID}) => {
const [isTicked, setTicked] = useState(false);
const onTick = () => setTicked(!isTicked);
useEffect( () => {
if(isTicked) {
ProcessSet.add(lID);
}
else { 
ProcessSet.delete(lID); 
}
console.log(ProcessSet); // Checking for changes in set.
}, [isTicked]);
return (
<div onClick={onTick}>
//some content
</div>
)
}
const PROCESS_COMPONENT = () => {
const [len, setLen] = useState(ProcessSet.size);
useEffect( () => {
setLen(ProcessSet.size);
}, [ProcessSet]); // This change is never being picked up.
return (
<div>
<h6> {len} items checked </h6>
</div>
)
}
export { CheckBox, PROCESS_COMPONENT };

Set本身确实从Checkbox中获得了正确的ID值。但PROCESS_COMPONENT似乎没有接收到集合中的变化,len显示0(集合的初始大小(。

我还没反应过来。但是,我们非常感谢您的帮助。

编辑:

基于@jdkramhoft的答案,我在Listings函数中将该集设置为状态变量。

const ListItem = ({lItem,set,setPSet}) => {
//...
<CheckBox lID={lItem.id} pset={set} setPSet={setPSet} />
)
}
function Listings() {
const [processSet, setPSet] = useState(new Set());
//....
<PROCESS_COMPONENT set={processSet} />
dataArray.map(item => { 
return <ListItem lItem={item} set={processSet} setPSet={setPSet} /> 
})
}

以及Process.jsx的相应变化

const CheckBox = ({lID,pset,setPSet}) => {
//...
if (isTicked) {
setPSet(pset.add(lID)); 
}
else {
setPSet(pset.delete(lID));
}
//...
}
const PROCESS_COMPONENT = ({set}) => {
//...
setLen(set.size);
//...
}

现在,每当我点击复选框时,我都会收到一个错误:

TypeError: pset.add is not a function. (In 'pset.add(lID)', 'pset.add' is undefined)

删除函数也会出现类似的错误。

首先,如果您希望使用检测到的更改进行反应以正确地重新渲染,则该集应为反应状态const [mySet, setMySet] = useState(new Set());。如果您需要该集可用于多个组件,您可以使用道具或上下文将其传递给它们。

其次,React检查像[ProcessSet]这样的依赖关系是否已经用===这样的东西改变了。即使集合中的项目不同,也不会检测到任何更改,因为对象是相同的,并且没有重新渲染。

更新:

[state, setState] = useState([]);setState部分不是为了突变前一个状态,只是为了提供下一个状态。因此,要更新您的设置,您可以执行以下操作:

const [set, setSet] = useState(new Set())
const itemToAdd = ' ', itemToRemove = ' ';
setSet(prev => new Set([...prev, itemToAdd]));
setSet(prev => new Set([...prev].filter(item => item !== itemToRemove)));

正如您可能注意到的那样,这使得添加和删除集合的速度与列表一样慢。所以,除非你需要用set.has()进行大量检查,否则我建议你使用一个列表:

const [items, setItems] = useState([])
const itemToAdd = ' ', itemToRemove = ' ';
setItems(prev => [...prev, itemToAdd]);
setItems(prev => prev.filter(item => item !== itemToRemove));

最新更新