为什么 forEach 循环只在找到状态时设置最后一个值。响应式JS
Why does forEach loop only set the last value if finds to state. ReactJS
const CategoriesData = [
{
name: "Category1",
isActive: true,
children: [
{
name: "Category1Child",
isActive: false,
}
]
},
{
name: "Category2",
isActive: false,
},
{
name: "Category3",
isActive: true,
children: [
{
name: "Category3Child",
isActive: false,
}
]
}
];
const [disabledCategories, setDisabledCategories] = useState([]);
function notActiveCategories(categories) {
// Loop logs out at least 7 isActive: false categories.
categories.forEach((category) => {
if (category.isActive) notActiveCategories(category.children);
if (!category.isActive) {
setDisabledCategories([...disabledCategories, category]);
console.log(category);
}
});
};
useEffect(() => {
notActiveCategories(CategoriesData);
console.log(disabledCategories); // Only 1 category is in the array.
}, []);
我觉得循环调用自身的函数导致 disabledCategories 状态恢复为空时,这导致仅设置 foreach 的最后一步。
那么我如何让它遍历类别数组并使 disabledCategories 状态包含所有具有 isActive: false 的类别对象。
在上面的 CategoriesData 示例中,这意味着 disabledCategories 状态将包含:
[
{
name: "Category1Child",
isActive: false,
},
{
name: "Category2",
isActive: false,
},
{
name: "Category3Child",
isActive: false,
},
];
方式一:递归循环后影响
function notActiveCategoriesRecusive(categories) {
let notActive = []
categories.forEach((category) => {
if (category.isActive) notActive = [...notActive, ...(notActiveCategories(category.children))];
if (!category.isActive) {
notActive.push(category)
}
});
return notActive
};
function notActiveCategories(categories) {
setDisabledCategories(notActiveCategoriesRecusive(categories)
}
方式二:获取最后一个状态因为没有时间刷新
function notActiveCategories(categories) {
categories.forEach((category) => {
if (category.isActive) notActiveCategories(category.children);
if (!category.isActive) {
setDisabledCategories(oldState => ([...oldState, category]))
}
});
};
尝试更改您的 setDisabledCategories
以使用来自 setState
:
的先前状态参数
setDisabledCategories(prevState => [...prevState, category])
当多个 setState
调用一起批处理时,您需要小心,以免它们相互覆盖。使用此方法可确保您的 setState 调用是“链接”的,因此您始终可以获得更新的状态。
我只会用过滤后的数组调用 setState
一次:
const findInactive = data =>
data.filter(e => !e.isActive)
.concat(...data.filter(e => e.children)
.map(e => findInactive(e.children)))
;
const categoriesData = [ { name: "Category1", isActive: true, children: [ { name: "Category1Child", isActive: false, } ] }, { name: "Category2", isActive: false, }, { name: "Category3", isActive: true, children: [ { name: "Category3Child", isActive: false, } ] } ];
const inactive = findInactive(categoriesData)
// the following is neeeded if it's possible for a
// node to have children and be inactive
// .map(({name, isActive}) => ({name, isActive}))
;
console.log(inactive);
//setDisabledCategories(inactive); // one time in React
这使得代码更容易推理,并将 React 的 API 从过滤逻辑中解耦出来,过滤逻辑可以移出到与 React 无关的通用函数中。
正如其他人提到的,如果您做想多次调用setState
作为批量更新,您可以使用prevState
回调来链接更新:setDisabledCategories(prevState => [...prevState, category]);
.
const CategoriesData = [
{
name: "Category1",
isActive: true,
children: [
{
name: "Category1Child",
isActive: false,
}
]
},
{
name: "Category2",
isActive: false,
},
{
name: "Category3",
isActive: true,
children: [
{
name: "Category3Child",
isActive: false,
}
]
}
];
const [disabledCategories, setDisabledCategories] = useState([]);
function notActiveCategories(categories) {
// Loop logs out at least 7 isActive: false categories.
categories.forEach((category) => {
if (category.isActive) notActiveCategories(category.children);
if (!category.isActive) {
setDisabledCategories([...disabledCategories, category]);
console.log(category);
}
});
};
useEffect(() => {
notActiveCategories(CategoriesData);
console.log(disabledCategories); // Only 1 category is in the array.
}, []);
我觉得循环调用自身的函数导致 disabledCategories 状态恢复为空时,这导致仅设置 foreach 的最后一步。
那么我如何让它遍历类别数组并使 disabledCategories 状态包含所有具有 isActive: false 的类别对象。 在上面的 CategoriesData 示例中,这意味着 disabledCategories 状态将包含:
[
{
name: "Category1Child",
isActive: false,
},
{
name: "Category2",
isActive: false,
},
{
name: "Category3Child",
isActive: false,
},
];
方式一:递归循环后影响
function notActiveCategoriesRecusive(categories) {
let notActive = []
categories.forEach((category) => {
if (category.isActive) notActive = [...notActive, ...(notActiveCategories(category.children))];
if (!category.isActive) {
notActive.push(category)
}
});
return notActive
};
function notActiveCategories(categories) {
setDisabledCategories(notActiveCategoriesRecusive(categories)
}
方式二:获取最后一个状态因为没有时间刷新
function notActiveCategories(categories) {
categories.forEach((category) => {
if (category.isActive) notActiveCategories(category.children);
if (!category.isActive) {
setDisabledCategories(oldState => ([...oldState, category]))
}
});
};
尝试更改您的 setDisabledCategories
以使用来自 setState
:
setDisabledCategories(prevState => [...prevState, category])
当多个 setState
调用一起批处理时,您需要小心,以免它们相互覆盖。使用此方法可确保您的 setState 调用是“链接”的,因此您始终可以获得更新的状态。
我只会用过滤后的数组调用 setState
一次:
const findInactive = data =>
data.filter(e => !e.isActive)
.concat(...data.filter(e => e.children)
.map(e => findInactive(e.children)))
;
const categoriesData = [ { name: "Category1", isActive: true, children: [ { name: "Category1Child", isActive: false, } ] }, { name: "Category2", isActive: false, }, { name: "Category3", isActive: true, children: [ { name: "Category3Child", isActive: false, } ] } ];
const inactive = findInactive(categoriesData)
// the following is neeeded if it's possible for a
// node to have children and be inactive
// .map(({name, isActive}) => ({name, isActive}))
;
console.log(inactive);
//setDisabledCategories(inactive); // one time in React
这使得代码更容易推理,并将 React 的 API 从过滤逻辑中解耦出来,过滤逻辑可以移出到与 React 无关的通用函数中。
正如其他人提到的,如果您做想多次调用setState
作为批量更新,您可以使用prevState
回调来链接更新:setDisabledCategories(prevState => [...prevState, category]);
.