多个变体循环中的 useState 不起作用 - 与 NextJs 反应
useState in multiple variants loop not working - React with NextJs
我的一个组件中有多个变体,我希望如果我单击任何变体,它应该向其添加 active class 并从另一个组件中删除 active class 。但是我对在多个变体循环中使用状态如何发生感到困惑。
这是我的代码:
import { useState } from "react";
const Variants = () => {
// Sample Variants Object - But in real it's coming from Wordpress back-end GraphQL
const vats = {
"Tech": ['3G', '5G'],
"Color": ['Red', 'Gray']
}
const [selectedTech, techToChange] = useState(null);
return (
<div>
{vats && (
<div>
{Object.keys(vats).map((key, value) => (
<div key={key}>
<div><b>{key}</b></div>
{vats[key].map((val) => (
<div key={val} onClick={() => techToChange('active')}>
<label
className="cursor-pointer bg-yellow-100"
>
{val} - {selectedTech}
</label>
</div>
))}
<hr/>
</div>
))}
</div>
)}
<hr />
</div>
)
}
你可以在我的代码中看到,有2个名为Tech & Color
的变体,例如;如果我点击 tech 的 3G
,它应该向其添加 active class 并从 5G
中删除 active class & 如果我点击 Red
它应该添加active class 并从 Gray
中删除 active class。有人可以帮我做吗?我卡住了
这是 return 代码。您需要传递 val 来设置 selectedTech
状态变量的状态,然后将实际值与其进行比较以设置活动 class。
const [selectedTech, techToChange] = useState([]);
const selectOps = (key,val) => {
let existing = selectedTech;
let idx = existing.findIndex(i => i.key===key);
console.log(idx);
if(idx > -1){
existing.splice(idx,1);
console.log(idx, existing);
}
techToChange([...existing, {key,val}]);
}
return (
<div>
{vats && (
<div>
{Object.keys(vats).map((key, value) => (
<div key={key}>
<div><b>{key}</b></div>
{vats[key].map((val) => (
<div key={val} onClick={() => selectOps(key,val)}>
<label
className={`cursor-pointer bg-yellow-100 ${selectedTech.some(s => s.val===val) ? 'active' : undefined}`}
>
{val}
</label>
</div>
))}
<hr/>
</div>
))}
</div>
)}
<hr />
</div>
)
来自 react-use
的 useMap
非常适合您现有的代码:
const [vats, {set, setAll, remove, reset}] = useMap({
"Tech": ['3G', '5G'],
"Color": ['Red', 'Gray']
}
...
{Object.keys(vats).map((key, value) => (
...
<div key={val} onClick={() => set(key, val)}>
您只是将 selectedTech
设置为 'active'
——这只是一个字符串,不会在点击的技术和处于状态的 selectedTech
之间创建任何类型的关系。
要解决此问题,您需要将 selectedTech
设置为您单击的那个的实际 val
。要添加你想要的变体分离,状态可以模仿你的变体的形状并且是一个对象。因此,您可以将 selectedTech[variant]
设置为您单击的值,而不是直接设置 selectedTech
。
然后,通过一些评估,您可以打印出字符串,active
当您单击一个时。
import { useState } from "react";
export default () => {
// Sample Variants Object - But in real it's coming from Wordpress back-end GraphQL
const vats = {
Tech: ["3G", "5G"],
Color: ["Red", "Gray"]
};
const initialState = Object.fromEntries(Object.keys(vats).map((key)=> [key, null])); const [selectedTech, techToChange] = useState(initialState);
return (
<div>
{vats && (
<div>
{Object.keys(vats).map((key, value) => (
<div key={key}>
<div>
<b>{key}</b>
</div>
{vats[key].map((val) => (
<div key={val} onClick={() => techToChange((c) => ({...c, [key]: val}))}>
<label className="cursor-pointer bg-yellow-100">
{val} - {selectedTech[key] === val ? "active" : null}
</label>
</div>
))}
<hr />
</div>
))}
</div>
)}
<hr />
</div>
);
};
代码沙箱:https://codesandbox.io/s/inspiring-kare-hsphp?file=/src/App.js
这是使用 useRef 和其他一些您可能会觉得有用的东西的示例:
import React, { useState, useRef, useEffect} from "react";
const Variants = () => {
// Sample Variants Object - But in real it's coming from Wordpress back-
end GraphQL
const vats = {
"Tech": ['3G', '5G'],
"Color": ['Red', 'Gray']
}
const labelRef = useRef();
const [selectedTech, techToChange] = useState("");
const [selectedColor, colorToChange] = useState("");
useEffect(()=>{
console.log(selectedColor);
if(labelRef.current.innerHTML.trim() === selectedColor) {
labelRef.current.className ="other class";
}
else {
labelRef.current.className ="cursor-pointer bg-yellow-100";
}
},
[selectedColor, labelRef])
useEffect(()=>{
console.log(selectedTech);
if(labelRef.current.innerHTML.trim() === selectedTech) {
labelRef.current.className ="other class";
}
else {
labelRef.current.className ="cursor-pointer bg-yellow-100";
}
},
[selectedTech, labelRef])
return (
<div>
{vats && (
<div>
{Object.keys(vats).map((key, value) => (
<div key={key}>
<div><b>{key}</b></div>
{vats[key].map((val) => (
<div key={val} onClick={(e) => {
if(key==="Tech") {
//console.log(e.target.innerHTML);
techToChange(e.target.innerHTML.trim());
labelRef.current = e.target;
//console.log(val.trim(),selectedTech.trim());
}
else if(key==="Color")
{
colorToChange(e.target.innerHTML.trim())
labelRef.current = e.target;
}
}
}>
<label ref={labelRef}
className="cursor-pointer bg-yellow-100"
>{val}
</label>
</div>
))}
<hr/>
</div>
))}
</div>
)}
<hr />
</div>
)
}
export default Variants;
我的一个组件中有多个变体,我希望如果我单击任何变体,它应该向其添加 active class 并从另一个组件中删除 active class 。但是我对在多个变体循环中使用状态如何发生感到困惑。
这是我的代码:
import { useState } from "react";
const Variants = () => {
// Sample Variants Object - But in real it's coming from Wordpress back-end GraphQL
const vats = {
"Tech": ['3G', '5G'],
"Color": ['Red', 'Gray']
}
const [selectedTech, techToChange] = useState(null);
return (
<div>
{vats && (
<div>
{Object.keys(vats).map((key, value) => (
<div key={key}>
<div><b>{key}</b></div>
{vats[key].map((val) => (
<div key={val} onClick={() => techToChange('active')}>
<label
className="cursor-pointer bg-yellow-100"
>
{val} - {selectedTech}
</label>
</div>
))}
<hr/>
</div>
))}
</div>
)}
<hr />
</div>
)
}
你可以在我的代码中看到,有2个名为Tech & Color
的变体,例如;如果我点击 tech 的 3G
,它应该向其添加 active class 并从 5G
中删除 active class & 如果我点击 Red
它应该添加active class 并从 Gray
中删除 active class。有人可以帮我做吗?我卡住了
这是 return 代码。您需要传递 val 来设置 selectedTech
状态变量的状态,然后将实际值与其进行比较以设置活动 class。
const [selectedTech, techToChange] = useState([]);
const selectOps = (key,val) => {
let existing = selectedTech;
let idx = existing.findIndex(i => i.key===key);
console.log(idx);
if(idx > -1){
existing.splice(idx,1);
console.log(idx, existing);
}
techToChange([...existing, {key,val}]);
}
return (
<div>
{vats && (
<div>
{Object.keys(vats).map((key, value) => (
<div key={key}>
<div><b>{key}</b></div>
{vats[key].map((val) => (
<div key={val} onClick={() => selectOps(key,val)}>
<label
className={`cursor-pointer bg-yellow-100 ${selectedTech.some(s => s.val===val) ? 'active' : undefined}`}
>
{val}
</label>
</div>
))}
<hr/>
</div>
))}
</div>
)}
<hr />
</div>
)
react-use
的 useMap
非常适合您现有的代码:
const [vats, {set, setAll, remove, reset}] = useMap({
"Tech": ['3G', '5G'],
"Color": ['Red', 'Gray']
}
...
{Object.keys(vats).map((key, value) => (
...
<div key={val} onClick={() => set(key, val)}>
您只是将 selectedTech
设置为 'active'
——这只是一个字符串,不会在点击的技术和处于状态的 selectedTech
之间创建任何类型的关系。
要解决此问题,您需要将 selectedTech
设置为您单击的那个的实际 val
。要添加你想要的变体分离,状态可以模仿你的变体的形状并且是一个对象。因此,您可以将 selectedTech[variant]
设置为您单击的值,而不是直接设置 selectedTech
。
然后,通过一些评估,您可以打印出字符串,active
当您单击一个时。
import { useState } from "react";
export default () => {
// Sample Variants Object - But in real it's coming from Wordpress back-end GraphQL
const vats = {
Tech: ["3G", "5G"],
Color: ["Red", "Gray"]
};
const initialState = Object.fromEntries(Object.keys(vats).map((key)=> [key, null])); const [selectedTech, techToChange] = useState(initialState);
return (
<div>
{vats && (
<div>
{Object.keys(vats).map((key, value) => (
<div key={key}>
<div>
<b>{key}</b>
</div>
{vats[key].map((val) => (
<div key={val} onClick={() => techToChange((c) => ({...c, [key]: val}))}>
<label className="cursor-pointer bg-yellow-100">
{val} - {selectedTech[key] === val ? "active" : null}
</label>
</div>
))}
<hr />
</div>
))}
</div>
)}
<hr />
</div>
);
};
代码沙箱:https://codesandbox.io/s/inspiring-kare-hsphp?file=/src/App.js
这是使用 useRef 和其他一些您可能会觉得有用的东西的示例:
import React, { useState, useRef, useEffect} from "react";
const Variants = () => {
// Sample Variants Object - But in real it's coming from Wordpress back-
end GraphQL
const vats = {
"Tech": ['3G', '5G'],
"Color": ['Red', 'Gray']
}
const labelRef = useRef();
const [selectedTech, techToChange] = useState("");
const [selectedColor, colorToChange] = useState("");
useEffect(()=>{
console.log(selectedColor);
if(labelRef.current.innerHTML.trim() === selectedColor) {
labelRef.current.className ="other class";
}
else {
labelRef.current.className ="cursor-pointer bg-yellow-100";
}
},
[selectedColor, labelRef])
useEffect(()=>{
console.log(selectedTech);
if(labelRef.current.innerHTML.trim() === selectedTech) {
labelRef.current.className ="other class";
}
else {
labelRef.current.className ="cursor-pointer bg-yellow-100";
}
},
[selectedTech, labelRef])
return (
<div>
{vats && (
<div>
{Object.keys(vats).map((key, value) => (
<div key={key}>
<div><b>{key}</b></div>
{vats[key].map((val) => (
<div key={val} onClick={(e) => {
if(key==="Tech") {
//console.log(e.target.innerHTML);
techToChange(e.target.innerHTML.trim());
labelRef.current = e.target;
//console.log(val.trim(),selectedTech.trim());
}
else if(key==="Color")
{
colorToChange(e.target.innerHTML.trim())
labelRef.current = e.target;
}
}
}>
<label ref={labelRef}
className="cursor-pointer bg-yellow-100"
>{val}
</label>
</div>
))}
<hr/>
</div>
))}
</div>
)}
<hr />
</div>
)
}
export default Variants;