如何解决如何在功能组件中使用 onClick 正确更新状态变量
我创建了两个选项卡,点击时需要为每个选项显示一组不同的产品和一组不同的过滤器。我的问题是,当我单击任一选项卡并在 changeTab 中调用 setoptions 时,我需要单击每个选项卡两次,然后它才会更新“选项”,“选项”需要包含每个过滤器。
显然在点击处理程序中调用 setoptions 是不正确的,但我不知道在哪里或如何正确更新“选项”。非常感谢帮助。
在“dedupedOptions”下方的控制台日志中,单击时会正确更新
function filterProducts() {
const [categoryType,setCategory] = useState("Canine");
const [activeTabIndex,setActiveTabIndex] = useState(0);
const {
productData: {
products: { products }
}
} = useContext(AppContext);
const productsByCategory = products
.filter((product) => {
const { tags } = product;
return !!tags.find((tag) => tag.includes(categoryType));
})
.map((product) => ({
...product,category: product.tags
.find((tag) => tag.includes("category:"))
.split(":")[1]
}));
let dedupedOptions = [];
productsByCategory.forEach((product) => {
const { tags } = product;
tags.forEach((tag) => {
const parts = tag.split(":");
const key = parts[0];
const value = parts[1] || null;
const validTag = tagKeysTodisplay.find(
(tagKeyTodisplay) => tagKeyTodisplay === key
);
if (
validTag &&
!dedupedOptions.find((dedupedOption) => dedupedOption.value === value)
) {
dedupedOptions = [
...dedupedOptions,{
label: titleCase(value),value,selected: false
}
];
}
});
});
const [options,setoptions] = useState(dedupedOptions);
console.log(dedupedOptions);
console.log(options);
const changeTab = (index,category) => {
setCategory(category);
setActiveTabIndex(index);
setoptions(dedupedOptions);
};
const setFilter = useCallback(
(selectedOption) => {
const optionIsActive = options.find(
(option) => option.value === selectedOption.value
)?.selected;
let newOptions = [];
newOptions = [
...options.map((option) => {
if (option.value === selectedOption.value) {
return {
...option,selected: !optionIsActive
};
}
return option;
})
];
setoptions(newOptions);
},[options]
);
}
并且这两个元素设置为选项卡来处理点击事件。这些在同一个 filterProducts 函数中呈现。
<div className="filter-products__tabs">
<div
className={`filter-products__tab
${activeTabIndex === 0 ? "is-active" : ""}`}
onClick={changeTab.bind(this,"Canine")}
>
<span>DOG</span>
</div>
<div
className={`filter-products__tab
${activeTabIndex === 1 ? "is-active" : ""}`}
onClick={changeTab.bind(this,1,"Feline")}
>
<span>CAT</span>
</div>
</div>
解决方法
我通过状态变量声明的一些更改重现了您的问题。 注意在 state 中声明变量并通过监听 useEffect 内部的变量变化来进行更新。
这是工作代码:\
https://codesandbox.io/s/quirky-http-e264i?file=/src/App.js
import "./styles.css";
import { useState,useContext,useCallback,useEffect } from "react";
export default function App() {
const [categoryType,setCategory] = useState("Canine");
const [activeTabIndex,setActiveTabIndex] = useState(0);
const [productsByCategory,setProductsByCategory] = useState([]);
const [dedupedOptions,setDedupedOptions] = useState([]);
const [options,setOptions] = useState(dedupedOptions);
const products = [
{ tags: ["category:Feline"],name: "one" },{ tags: ["category:Canine"],name: "two" }
];
useEffect(() => {
const productsByCategory = products
.filter((product) => {
const { tags } = product;
return !!tags.find((tag) => tag.includes(categoryType));
})
.map((product) => ({
...product,category: product.tags
.find((tag) => tag.includes("category:"))
.split(":")[1]
}));
setProductsByCategory(productsByCategory);
},[categoryType]);
useEffect(() => {
let tmp_dedupedOptions = [];
const tagKeysToDisplay = ["category"];
productsByCategory.forEach((product) => {
const { tags } = product;
tags.forEach((tag) => {
const parts = tag.split(":");
const key = parts[0];
const value = parts[1] || null;
const validTag = tagKeysToDisplay.find(
(tagKeyToDisplay) => tagKeyToDisplay === key
);
if (
validTag &&
!tmp_dedupedOptions.find(
(dedupedOption) => dedupedOption.value === value
)
) {
tmp_dedupedOptions = [
...tmp_dedupedOptions,{
label: value,value,selected: false
}
];
}
});
});
setDedupedOptions(tmp_dedupedOptions);
setOptions(tmp_dedupedOptions);
},[productsByCategory]);
console.log("options: ",options);
const changeTab = (index,category) => {
setCategory(category);
setActiveTabIndex(index);
};
const setFilter = useCallback(
(selectedOption) => {
const optionIsActive = options.find(
(option) => option.value === selectedOption.value
)?.selected;
let newOptions = [];
newOptions = [
...options.map((option) => {
if (option.value === selectedOption.value) {
return {
...option,selected: !optionIsActive
};
}
return option;
})
];
setOptions(newOptions);
},[options]
);
// }
return (
<div>
<div className="filter-products__tabs">
<div
className={`filter-products__tab
${activeTabIndex === 0 ? "is-active" : ""}`}
onClick={changeTab.bind(this,"Canine")}
>
<span>DOG</span>
</div>
<div
className={`filter-products__tab
${activeTabIndex === 1 ? "is-active" : ""}`}
onClick={changeTab.bind(this,1,"Feline")}
>
<span>CAT</span>
</div>
</div>
</div>
);
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。