首页 > 解决方案 > 使用 React 和 map 时如何只折叠一个 div

问题描述

我正在尝试使用 React 创建一个动态菜单,并且我正在努力实现折叠功能。我首先使用一个可以正常工作的 Json 对象映射每个 MenuItem。之后,当我尝试在单击时实现折叠功能时,所有菜单项都会折叠,而不仅仅是单击的菜单项。我尝试实现一个在真/假之间切换的数组,但是在单击时我无法访问该值。这是代码:

import React, { Component } from "react";
import styled from "styled-components";
import "./sidebar.css";
import Collapse from 'react-bootstrap/Collapse'
const dashboardItems = [
    {
        id: 1,
        title: "Dashboard",
        subtitles: ["Analysis", "Monitor", "Workpplace"],
        text: "Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident."
    },
    {
        id: 2,
        title: "Form",
        subtitles: ["Basic Form", "Step Form", "Advanced Form"],
        text: "enim eiusmod high life accusamus terry richardson ad squid. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident."

    },
    {
        id: 3,
        title: "List",
        subtitles: ["Search Table", "Basic List", "Card List"],
        text: "richardson ad squid. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident."
    },
    {
        id: 4,
        title: "Profile",
        subtitles: ["Basic Profile", "Advanced Profile"],
        text: "Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident."
    },
    {
        id: 5,
        title: "Result",
        subtitles: ["Success", "Failure"],
        text: "craft beer labore wes anderson cred nesciunt sapiente ea proident."
    },
    {
        id: 6,
        title: "Account",
        subtitles: ["Account Center", "Account Settings"],
        text: "wes anderson cred nesciunt sapiente ea proident."
    }
];


function Sidebar(){
        const [open, setOpen] = React.useState(false);
        const [clickedItems, setClickedItems] = React.useState( [false, false, false, false, false, false] );
        function handleClick(id) {
            console.log("initial value at " + id + " is " + clickedItems[id - 1] + " array is " + clickedItems)
            clickedItems[id - 1] = !clickedItems[id - 1];
            console.log(clickedItems);
            setOpen(!open)
        }

        return (
           <SidebarContainer>
               <SidebarMenu>
                   <MenuLogo>
                   Dashboard
                   </MenuLogo>                

                    {dashboardItems.map((postData) => {
                        return(
                            <div key = {postData.id} >
                                <SidebarMenuItem 
                                    onClick={() => handleClick(postData.id)}
                                >
                                        <SidebarMenuItemLabel>{postData.title}</SidebarMenuItemLabel>
                                </SidebarMenuItem>
                                <Collapse in={open}>
a                                    <div key={postData.id} id="example-collapse-text" className="collapsedText">
                                        {postData.text}
                                    </div>
                                </Collapse>
                           </div>
                        );
                    })}
                </SidebarMenu>
            </SidebarContainer>
        );
}


const SidebarContainer = styled.div`
        height: 100vh;
        width: 270px;
        background-color: #252529;
        color: #fff;
        display: flex;
        flex-direction: column;
        font-family: "Roboto", sans-serif;
`;

const SidebarMenu = styled.ul`
        display: flex;
        align-items: left;
        flex-direction: column;
        list-style: none;
        width: 100%;
        padding-left: 0px;
`;

const MenuLogo = styled.div`
        display: flex;
        align-items: center;
        justify-content: start;
        gap: 16px;
        font-size: 18px;
        line-height: 1.5;
        font-weight: 600;
        height: 45px;
        color: #fff;
        margin: 30px 30px 30px 30px;
        padding-bottom: 20px;
        border-bottom: 1px solid #2e2e33;
`;

const SidebarMenuItem = styled.li`
        display: flex;
        height: 40px;
        width: 100%;
        align-items: center;
        padding-left: 30px;
        &:hover {
        background: rgba(255, 255, 255, 0.05);
        box-shadow: inset 3px 0 0 0 #ffffff;
        cursor: pointer;
}
`;

const SidebarMenuItemLabel = styled.p`
        font-family: "Open Sans", sans-serif;
        color: #fff;
        font-size: 16px;
        font-weight: 600;
        line-height: 1.3;
        text-align: left;
        padding: 15px 0px;
        margin-left: 15px;
        margin-top: 15px;
        color: #ffffff;
`;


export default Sidebar;

如果您可能知道解决方案,请告诉我。谢谢!

标签: javascriptreactjsreact-bootstrap

解决方案


您的“打开”变量应该是一个空对象。


const [open, setOpen] = React.useState({});

然后在 handleClick 函数上创建一个以“id”为键的新字段。

function handleClick(id) {
            setOpen((prevState => ({...prevState, [id]: !prevState[id]}))
        }

然后将其用作“开放”道具。


 <Collapse in={open[postData.id]}>
  <div key={postData.id} id="example-collapse-text" className="collapsedText">
    {postData.text}
  </div>
 </Collapse>

请记住,当您想要访问实际状态时,您总是希望这样做:

const [state, setState] = useState(true)
setState(prevState => !prevState)

永不

const [state, setState] = useState(true)
setState(!state) // <-- THIS IS BAD

推荐阅读