我正在尝试在边栏中创建可折叠列表。单击时,我正在更改“ isOpen”状态,并根据此状态显示或隐藏子链接。问题是所有子链接都同时打开。
在此处检查沙箱:https://codesandbox.io/s/infallible-moore-h16g6
const Sidebar = ({ title, children, data, opened, ...attrs }) => {
const [isOpen, setTriger] = useState(false);
const handleClick = idx => {
setTriger(!isOpen)
};
return (
<SidebarUI>
{data.map((item, idx) => {
return typeof item.data === "string" ?
<div key={idx} >{item.name}</div>:
<Fragment key={idx}>
<div onClick={() => handleClick(idx)}>{item.name}</div>
{ item.data.map((subs, ids) => {
return <Test isOpen={isOpen} key={ids}>++++{subs.name}</Test>;
})}
</Fragment>
})}
</SidebarUI>
);
};
答案 0 :(得分:4)
尝试创建具有折叠元素状态的对象,如下所示:
const Sidebar = ({ title, children, data, opened, ...attrs }) => {
const [collapseElements, setCollapse] = useState({});
const handleClick = idx => {
const currentElements = Object.assign({}, collapseElements);
setCollapse({ ...currentElements, [idx]: !collapseElements[idx] });
};
return (
<SidebarUI>
{data.map((item, idx) => {
return typeof item.data === "string" ? (
<div key={idx}>{item.name}</div>
) : (
<Fragment key={idx}>
<div onClick={() => handleClick(idx)}>{item.name}</div>
{item.data.map((subs, ids) => {
return (
<Test isOpen={collapseElements[idx]} key={ids}>
++++{subs.name}
</Test>
);
})}
</Fragment>
);
})}
</SidebarUI>
);
};
export default Sidebar;
结帐the sandbox。
让我知道是否有帮助。
答案 1 :(得分:1)
我做了一个新的codesandbox,直到我添加了一些过渡效果。现在打开和关闭都很顺利。
现在它可以打开和关闭。
您要做的是保留单击的index
,仅在它们相同的情况下显示子项index
。
我还添加了一种关闭和打开方法。
这里是使用您问题中的代码来完成的。
const Sidebar = ({ title, children, data, opened, ...attrs }) => {
const [openedIndex , setTriger] = useState(false);
const handleClick = idx => {
// this ternary makes it possible to open and close
setTriger(idx === openedIndex ? -1 : idx)
};
return (
<SidebarUI>
{data.map((item, idx) => {
return typeof item.data === "string" ?
<div key={idx} >{item.name}</div>:
<Fragment key={idx}>
<div onClick={() => handleClick(idx)}>{item.name}</div>
{// here you check if the idx is the same as the opened one}
{// before showing the data of the item}
{idx === openedIndex && item.data.map((subs, ids) => {
return <Test isOpen={true} key={ids}>++++{subs.name}</Test>;
})}
</Fragment>
})}
</SidebarUI>
);
};
答案 2 :(得分:0)
您可以在不使用状态的情况下解决此问题。尝试更改为此
<Fragment key={idx}>
<div class="sidebar-item" onClick={e => openSidebar(e)}>
{item.name}
</div>
{item.data.map((subs, ids) => {
return (
<div className="sidebar-subitem" key={ids}>
++++{subs.name}
</div>
);
})}
</Fragment>
点击切换类
function openSidebar(e) {
e.preventDefault();
e.target.classList.toggle("open");
}
添加CSS
.sidebar-subitem {
display: none;
}
.sidebar-item.open + .sidebar-subitem {
display: block;
}
答案 3 :(得分:0)
这当然并不比@axeljunes好,但它也可以工作,因此我维护了一个单独的已切换ID列表,并以此为基础进行切换。 这也是我第一次使用钩子让我裸露(随时可以纠正我)
const Sidebar = ({ title, children, data, opened, ...attrs }) => {
//const [isOpen, setTriger] = useState(false);
const [list, setList] = useState([]);
const handleClick = idx => {
//setTriger(!isOpen);
if(!list.includes(idx))
setList([...list,idx]);
else{
const newList = list.filter(e => e!==idx);
setList(newList);
}
};
return (
<SidebarUI>
{data.map((item, idx) => {
return typeof item.data === "string" ? (
<div key={idx}>{item.name}MAIN</div>
) : (
<Fragment key={idx}>
<div onClick={() => handleClick(idx)}>{item.name}IN</div>
{item.data.map((subs, ids) => {
return (
<Test isOpen={list.includes(idx)} key={ids}>
++++{subs.name}SIDE
</Test>
);
})}
</Fragment>
);
})}
</SidebarUI>
);
};
export default Sidebar;