在React.js中悬停时显示菜单

huangapple go评论82阅读模式
英文:

Display menu on hover reactjs

问题

在一个React应用中,我正在使用reactstrap CSS框架来创建下拉菜单以列出下拉菜单。

Example.Js

<Dropdown
  className="d-inline-block"
  onMouseOver={this.onMouseEnter}
  onMouseLeave={this.onMouseLeave}
  isOpen={this.state.dropdownOpen}
  toggle={this.toggle}
>
  <DropdownToggle caret>Dropdown1</DropdownToggle>
  <DropdownMenu>
    <DropdownItem header>Submenu 1</DropdownItem>
    <DropdownItem>Submenu 1.1</DropdownItem>
  </DropdownMenu>
  &nbsp;&nbsp;&nbsp;
  <DropdownToggle caret>Dropdown2</DropdownToggle>
  <DropdownMenu>
    <DropdownItem header>Submenu 2</DropdownItem>
    <DropdownItem>Submenu 2.1</DropdownItem>
    <DropdownItem>Submenu 2.2</DropdownItem>
  </DropdownMenu>
  &nbsp;&nbsp;&nbsp;
  <br /><br />
  <DropdownToggle caret>Dropdown3</DropdownToggle>
  <DropdownMenu>
    <DropdownItem header>Submenu 3</DropdownItem>
    <DropdownItem>Submenu 3.1</DropdownItem>
    <DropdownItem>Submenu 3.2</DropdownItem>
    <DropdownItem>Submenu 3.3</DropdownItem>
  </DropdownMenu>
</Dropdown>

在这里,我使用 setState 来在 onMouseOveronMouseLeave 等事件中设置 dropDownOpen 状态。

问题 在单个下拉菜单上悬停时,每个下拉菜单都会打开。

点击此处查看工作演示

请帮助我使悬停下拉菜单只列出悬停的菜单,而不是全部同时列出。

注意: 在我的实际应用中,这些下拉菜单将是动态的,所以我不能创建任何硬编码的状态,如 dropDown1dropDown2dropDown3 ... 等等。

可能会有任意数量的下拉菜单,所以请考虑动态菜单并给我提供解决方案。

英文:

In a react application, I am using reactstrap css framework to make the dropdowns to list the dropdown menus.

Example.Js

      &lt;Dropdown
        className=&quot;d-inline-block&quot;
        onMouseOver={this.onMouseEnter}
        onMouseLeave={this.onMouseLeave}
        isOpen={this.state.dropdownOpen}
        toggle={this.toggle}
      &gt;
        &lt;DropdownToggle caret&gt;Dropdown1&lt;/DropdownToggle&gt;
        &lt;DropdownMenu&gt;
          &lt;DropdownItem header&gt;Submenu 1&lt;/DropdownItem&gt;
          &lt;DropdownItem&gt;Submenu 1.1&lt;/DropdownItem&gt;
        &lt;/DropdownMenu&gt;
        &amp;nbsp;&amp;nbsp;&amp;nbsp;
        &lt;DropdownToggle caret&gt;Dropdown2&lt;/DropdownToggle&gt;
        &lt;DropdownMenu&gt;
          &lt;DropdownItem header&gt;Submenu 2&lt;/DropdownItem&gt;
          &lt;DropdownItem&gt;Submenu 2.1&lt;/DropdownItem&gt;
          &lt;DropdownItem&gt;Submenu 2.2&lt;/DropdownItem&gt;
        &lt;/DropdownMenu&gt;
        &amp;nbsp;&amp;nbsp;&amp;nbsp;
        &lt;br /&gt;&lt;br /&gt;
        &lt;DropdownToggle caret&gt;Dropdown3&lt;/DropdownToggle&gt;
        &lt;DropdownMenu&gt;
          &lt;DropdownItem header&gt;Submenu 3&lt;/DropdownItem&gt;
          &lt;DropdownItem&gt;Submenu 3.1&lt;/DropdownItem&gt;
          &lt;DropdownItem&gt;Submenu 3.2&lt;/DropdownItem&gt;
          &lt;DropdownItem&gt;Submenu 3.3&lt;/DropdownItem&gt;
        &lt;/DropdownMenu&gt;
      &lt;/Dropdown&gt;

Here I have made the setState to set the state for dropDownOpen in the events such as onMouseOver and onMouseLeave.

The issue is on hover of single dropdown menu, every dropdown gets opened.

Click here for Working Demo

Kindly help me to make the hover dropdown to only list the menus of hovered one and not all at a time.

Note: In my real application, these dropdown menus will be dynamic, So I cant make any hardcoded state like, dropDown1, dropDown2, dropDown3 ... etc ..

It may have any n number of dropdowns.. So please give me solution in keeping the dynamic menus into consideration.

答案1

得分: 1

基本上,每个下拉菜单都需要在自己的 Dropdown 组合组件中,具有自己的状态和处理程序。我分叉并更新了您的演示,希望能给您正确的思路。

<div>
    <Dropdown
        className="d-inline-block"
        onMouseOver={this.onMouseEnter}
        onMouseLeave={this.onMouseLeave}
        isOpen={this.state.dropdownOpen1}
        toggle={this.toggle1}
    >
        <DropdownToggle caret>Dropdown1</DropdownToggle>
        <DropdownMenu>
            <DropdownItem header>Submenu 1</DropdownItem>
            <DropdownItem>Submenu 1.1</DropdownItem>
        </DropdownMenu>
        &nbsp;&nbsp;&nbsp;
    </Dropdown>
    <Dropdown
        className="d-inline-block"
        // onMouseOver={this.onMouseEnter}
        // onMouseLeave={this.onMouseLeave}
        isOpen={this.state.dropdownOpen2}
        toggle={this.toggle2}
    >
        <DropdownToggle caret>Dropdown2</DropdownToggle>
        <DropdownMenu>
            <DropdownItem header>Submenu 2</DropdownItem>
            <DropdownItem>Submenu 2.1</DropdownItem>
            <DropdownItem>Submenu 2.2</DropdownItem>
        </DropdownMenu>
        &nbsp;&nbsp;&nbsp;
        <br /><br />
    </Dropdown>
    <Dropdown
        className="d-inline-block"
        // onMouseOver={this.onMouseEnter}
        // onMouseLeave={this.onMouseLeave}
        isOpen={this.state.dropdownOpen3}
        toggle={this.toggle3}
    >
        <DropdownToggle caret>Dropdown3</DropdownToggle>
        <DropdownMenu>
            <DropdownItem header>Submenu 3</DropdownItem>
            <DropdownItem>Submenu 3.1</DropdownItem>
            <DropdownItem>Submenu 3.2</DropdownItem>
            <DropdownItem>Submenu 3.3</DropdownItem>
        </DropdownMenu>
    </Dropdown>
</div>

链接:https://stackblitz.com/edit/reactstrap-v6-2dnzex?file=Example.js

英文:

Basically each dropdown menu needs to be in its own Dropdown composite component, with its own state and handlers. I forked and updated your demo that hopefully gives you the right idea.

&lt;div&gt;
&lt;Dropdown
className=&quot;d-inline-block&quot;
onMouseOver={this.onMouseEnter}
onMouseLeave={this.onMouseLeave}
isOpen={this.state.dropdownOpen1}
toggle={this.toggle1}
&gt;
&lt;DropdownToggle caret&gt;Dropdown1&lt;/DropdownToggle&gt;
&lt;DropdownMenu&gt;
&lt;DropdownItem header&gt;Submenu 1&lt;/DropdownItem&gt;
&lt;DropdownItem&gt;Submenu 1.1&lt;/DropdownItem&gt;
&lt;/DropdownMenu&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;/Dropdown&gt;
&lt;Dropdown
className=&quot;d-inline-block&quot;
// onMouseOver={this.onMouseEnter}
// onMouseLeave={this.onMouseLeave}
isOpen={this.state.dropdownOpen2}
toggle={this.toggle2}
&gt;
&lt;DropdownToggle caret&gt;Dropdown2&lt;/DropdownToggle&gt;
&lt;DropdownMenu&gt;
&lt;DropdownItem header&gt;Submenu 2&lt;/DropdownItem&gt;
&lt;DropdownItem&gt;Submenu 2.1&lt;/DropdownItem&gt;
&lt;DropdownItem&gt;Submenu 2.2&lt;/DropdownItem&gt;
&lt;/DropdownMenu&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br /&gt;&lt;br /&gt;
&lt;/Dropdown&gt;
&lt;Dropdown
className=&quot;d-inline-block&quot;
// onMouseOver={this.onMouseEnter}
// onMouseLeave={this.onMouseLeave}
isOpen={this.state.dropdownOpen3}
toggle={this.toggle3}
&gt;
&lt;DropdownToggle caret&gt;Dropdown3&lt;/DropdownToggle&gt;
&lt;DropdownMenu&gt;
&lt;DropdownItem header&gt;Submenu 3&lt;/DropdownItem&gt;
&lt;DropdownItem&gt;Submenu 3.1&lt;/DropdownItem&gt;
&lt;DropdownItem&gt;Submenu 3.2&lt;/DropdownItem&gt;
&lt;DropdownItem&gt;Submenu 3.3&lt;/DropdownItem&gt;
&lt;/DropdownMenu&gt;
&lt;/Dropdown&gt;
&lt;/div&gt;

https://stackblitz.com/edit/reactstrap-v6-2dnzex?file=Example.js

答案2

得分: 1

这是显示菜单或下拉菜单子菜单的解决方案。

请随时提出任何问题或如果您对此有任何疑问。

import React from 'react';
import { Box, jsx } from 'theme-ui';
import { Link } from 'gatsby';
import { H1 } from '../../components/ThemeHeader';
import { Image } from '../../components/';

const CardWithCTALinks = (props) => {
  const { cardWithCTALinksImage, ctaLinks, heading, bgColor } = props;
  const [onCTAListHover, setOnCTAListHover] = React.useState({ status: '', indexAt: -1 });

  const updateCTAListHover = (newOnCTAListHover, idx) => {
    if (newOnCTAListHover !== onCTAListHover) setOnCTAListHover({ state: newOnCTAListHover, indexAt: idx });
  };
  const renderImageSection = (src, alt) => {
    return <Image src={src} alt={alt} />;
  };
  const renderSubLinks = (subLinks, idx) => {
    return (
      <Box>
        {idx === onCTAListHover.indexAt &&
          subLinks.map((link) => (
            <Link key={Math.random().toString(36).substring(7)} to="/">
              {link.text}
            </Link>
          ))}
      </Box>
    );
  };
  const renderLinksSection = (linksList, headingText) => {
    return (
      <Box>
        {headingText && <H1>{headingText}</H1>}
        {linksList && (
          <Box>
            {linksList.map((link, index) => (
              <h1 onMouseEnter={() => updateCTAListHover(true, index)} onMouseLeave={() => updateCTAListHover(false, index)}>
                {link.node?.title}
                {link.node?.navItems.length > 0 && <>{onCTAListHover && renderSubLinks(link.node?.navItems, index)}</>}
              </h1>
            ))}
          </Box>
        )}
      </Box>
    );
  };

  return (
    <Box style={{ backgroundColor: bgColor }}>
      {cardWithCTALinksImage && <Box>{renderImageSection(cardWithCTALinksImage?.asset._ref, 'alt')}</Box>}
      {ctaLinks && heading && <Box>{renderLinksSection(ctaLinks.edges, heading)}</Box>}
    </Box>
  );
};

export default CardWithCTALinks;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

希望这有所帮助。

英文:

Here is my solution to show the submenu of the menu or dropdown.
Feel free to ask any questions or if you have any confusion about it.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

import React from &#39;react&#39;;
import { Box, jsx } from &#39;theme-ui&#39;;
import { Link } from &#39;gatsby&#39;;
import { H1 } from &#39;../../components/ThemeHeader&#39;;
import { Image } from &#39;../../components&#39;;
const CardWithCTALinks = (props) =&gt; {
const { cardWithCTALinksImage, ctaLinks, heading, bgColor } = props;
const [onCTAListHover, setOnCTAListHover] = React.useState({ status: &#39;&#39;, indexAt: -1 });
const updateCTAListHover = (newOnCTAListHover, idx) =&gt; {
if (newOnCTAListHover !== onCTAListHover) setOnCTAListHover({ state: newOnCTAListHover, indexAt: idx });
};
const renderImageSection = (src, alt) =&gt; {
return &lt;Image src={src} alt={alt} /&gt;;
};
const renderSubLinks = (subLinks, idx) =&gt; {
return (
&lt;Box&gt;
{idx === onCTAListHover.indexAt &amp;&amp;
subLinks.map((link) =&gt; (
&lt;Link key={Math.random().toString(36).substring(7)} to=&quot;/&quot;&gt;
{link.text}
&lt;/Link&gt;
))}
&lt;/Box&gt;
);
};
const renderLinksSection = (linksList, headingText) =&gt; {
return (
&lt;Box&gt;
{headingText &amp;&amp; &lt;H1&gt;{headingText}&lt;/H1&gt;}
{linksList &amp;&amp; (
&lt;Box&gt;
{linksList.map((link, index) =&gt; (
&lt;h1 onMouseEnter={() =&gt; updateCTAListHover(true, index)} onMouseLeave={() =&gt; updateCTAListHover(false, index)}&gt;
{link.node?.title}
{link.node?.navItems.length &gt; 0 &amp;&amp; &lt;&gt;{onCTAListHover &amp;&amp; renderSubLinks(link.node?.navItems, index)}&lt;/&gt;}
&lt;/h1&gt;
))}
&lt;/Box&gt;
)}
&lt;/Box&gt;
);
};
return (
&lt;Box style={{ backgroundColor: bgColor }}&gt;
{cardWithCTALinksImage &amp;&amp; &lt;Box&gt;{renderImageSection(cardWithCTALinksImage?.asset._ref, &#39;alt&#39;)}&lt;/Box&gt;}
{ctaLinks &amp;&amp; heading &amp;&amp; &lt;Box&gt;{renderLinksSection(ctaLinks.edges, heading)}&lt;/Box&gt;}
&lt;/Box&gt;
);
};
export default CardWithCTALinks;

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;

<!-- end snippet -->

答案3

得分: 0

import React from "react";
import {
  Dropdown,
  DropdownToggle,
  DropdownMenu,
  DropdownItem
} from "reactstrap";

export default class Example extends React.Component {
  constructor(props) {
    super(props);

    this.toggle = this.toggle.bind(this);
    this.onMouseEnter = this.onMouseEnter.bind(this);
    this.onMouseLeave = this.onMouseLeave.bind(this);
    this.state = {
      dropdownOpen1: false,
      dropdownOpen2: false,
      dropdownOpen3: false
    };
  }

  toggle(id) {
    this.setState({ [id]: !this.state[`${id}`] });
  }

  onMouseEnter(id) {
    this.setState({ [id]: true });
  }

  onMouseLeave(id) {
    this.setState({ [id]: false });
  }

  render() {
    return (
      <div>
        <Dropdown
          className="d-inline-block"
          onMouseOver={() => this.onMouseEnter("dropdownOpen1")}
          onMouseLeave={() => this.onMouseLeave("dropdownOpen1")}
          isOpen={this.state.dropdownOpen1}
          toggle={() => this.toggle("dropdownOpen1")}
        >
          <DropdownToggle caret>Dropdown1</DropdownToggle>
          <DropdownMenu>
            <DropdownItem header>Submenu 1</DropdownItem>
            <DropdownItem>Submenu 1.1</DropdownItem>
          </DropdownMenu>
        </Dropdown>
        <Dropdown
          className="d-inline-block"
          onMouseOver={() => this.onMouseEnter("dropdownOpen2")}
          onMouseLeave={() => this.onMouseLeave("dropdownOpen2")}
          isOpen={this.state.dropdownOpen2}
          toggle={() => this.toggle("dropdownOpen2")}
        >
          &nbsp;&nbsp;&nbsp;
          <DropdownToggle caret>Dropdown2</DropdownToggle>
          <DropdownMenu>
            <DropdownItem header>Submenu 2</DropdownItem>
            <DropdownItem>Submenu 2.1</DropdownItem>
            <DropdownItem>Submenu 2.2</DropdownItem>
          </DropdownMenu>
        </Dropdown>
        <Dropdown
          className="d-inline-block"
          onMouseOver={() => this.onMouseEnter("dropdownOpen3")}
          onMouseLeave={() => this.onMouseLeave("dropdownOpen3")}
          isOpen={this.state.dropdownOpen3}
          toggle={() => this.toggle("dropdownOpen3")}
        >
          &nbsp;&nbsp;&nbsp;
          <br />
          <br />
          <DropdownToggle caret>Dropdown3</DropdownToggle>
          <DropdownMenu>
            <DropdownItem header>Submenu 3</DropdownItem>
            <DropdownItem>Submenu 3.1</DropdownItem>
            <DropdownItem>Submenu 3.2</DropdownItem>
            <DropdownItem>Submenu 3.3</DropdownItem>
          </DropdownMenu>
        </Dropdown>
      </div>
    );
  }
}

尽量保持原始代码的格式和结构。

英文:
 import React from &quot;react&quot;;
import {
Dropdown,
DropdownToggle,
DropdownMenu,
DropdownItem
} from &quot;reactstrap&quot;;
export default class Example extends React.Component {
constructor(props) {
super(props);
this.toggle = this.toggle.bind(this);
this.onMouseEnter = this.onMouseEnter.bind(this);
this.onMouseLeave = this.onMouseLeave.bind(this);
this.state = {
dropdownOpen1: false,
dropdownOpen2: false,
dropdownOpen3: false
};
}
toggle(id) {
this.setState({[id]:!this.state[`${id}`]})
}
onMouseEnter(id) {
this.setState({ [id]: true });
}
onMouseLeave(id) {
this.setState({ [id]: false });
}
render() {
return (
&lt;div&gt;
&lt;Dropdown
className=&quot;d-inline-block&quot;
onMouseOver={()=&gt;this.onMouseEnter(&quot;dropdownOpen1&quot;)}
onMouseLeave={()=&gt;this.onMouseLeave(&quot;dropdownOpen1&quot;)}
isOpen={this.state.dropdownOpen1}
toggle={()=&gt;this.toggle(&quot;dropdownOpen1&quot;)}
&gt;
&lt;DropdownToggle caret&gt;Dropdown1&lt;/DropdownToggle&gt;
&lt;DropdownMenu&gt;
&lt;DropdownItem header&gt;Submenu 1&lt;/DropdownItem&gt;
&lt;DropdownItem&gt;Submenu 1.1&lt;/DropdownItem&gt;
&lt;/DropdownMenu&gt;
&lt;/Dropdown&gt;
&lt;Dropdown
className=&quot;d-inline-block&quot;
onMouseOver={()=&gt;this.onMouseEnter(&quot;dropdownOpen2&quot;)}
onMouseLeave={()=&gt;this.onMouseLeave(&quot;dropdownOpen2&quot;)}
isOpen={this.state.dropdownOpen2}
toggle={()=&gt;this.toggle(&quot;dropdownOpen2&quot;)}
&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;DropdownToggle caret&gt;Dropdown2&lt;/DropdownToggle&gt;
&lt;DropdownMenu&gt;
&lt;DropdownItem header&gt;Submenu 2&lt;/DropdownItem&gt;
&lt;DropdownItem&gt;Submenu 2.1&lt;/DropdownItem&gt;
&lt;DropdownItem&gt;Submenu 2.2&lt;/DropdownItem&gt;
&lt;/DropdownMenu&gt;
&lt;/Dropdown&gt;
&lt;Dropdown
className=&quot;d-inline-block&quot;
onMouseOver={()=&gt;this.onMouseEnter(&quot;dropdownOpen3&quot;)}
onMouseLeave={()=&gt;this.onMouseLeave(&quot;dropdownOpen3&quot;)}
isOpen={this.state.dropdownOpen3}
toggle={()=&gt;this.toggle(&quot;dropdownOpen3&quot;)}
&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br /&gt;
&lt;br /&gt;
&lt;DropdownToggle caret&gt;Dropdown3&lt;/DropdownToggle&gt;
&lt;DropdownMenu&gt;
&lt;DropdownItem header&gt;Submenu 3&lt;/DropdownItem&gt;
&lt;DropdownItem&gt;Submenu 3.1&lt;/DropdownItem&gt;
&lt;DropdownItem&gt;Submenu 3.2&lt;/DropdownItem&gt;
&lt;DropdownItem&gt;Submenu 3.3&lt;/DropdownItem&gt;
&lt;/DropdownMenu&gt;
&lt;/Dropdown&gt; 
&lt;/div&gt;
);
}
}

Try it out once !!!let me know,basically you need to pass different args for each dropdown ,so that your method can differentiate what to open or close.

答案4

得分: 0

嗨 @TestUser 和 Drew Reese,我已经使用箭头函数减少了一些行数:https://stackblitz.com/edit/reactstrap-dropdown?file=Example.js 如果您需要多个下拉菜单,您可以创建一个单一的下拉菜单,并使用props创建多个下拉菜单(您可以使用map进行重复操作),并且可以在多个地方使用它。这就是React的美妙之处。

英文:

Hi @TestUser and Drew Reese I have reduces some line using arrow functions: https://stackblitz.com/edit/reactstrap-dropdown?file=Example.js and if you need this for n dropdown then you can create single drop-down and using props you can create multiple dropdown for this (you can use map for repeating for this) and can use this multiple places. that is the beauty of react.

答案5

得分: 0

以下是翻译好的部分:

App.js

所以基本上你在所有三个下拉菜单中都使用了相同的状态变量

要解决这个问题你需要维护三个不同的状态变量因为你想要一种动态的方式你可以采用以下方法

另外为了可重用性你可以将下拉菜单作为一个单独的组件

如果需要你可以添加更多的逻辑这是解决问题的简单方法

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import { Container } from "reactstrap";
import CustomDropDown from "./CustomDropdown";
import "bootstrap/dist/css/bootstrap.min.css";

import "./styles.css";

const dropdownConfig = [
  {
    customKey: 1,
    options: [
      { title: "Submenu 1", header: true },
      { title: "Submenu 1.1", header: false }
    ],
    name: "dropdownOpen1"
  },
  {
    customKey: 2,
    options: [
      { title: "Submenu 2", header: true },
      { title: "Submenu 2.1", header: false }
    ],
    name: "dropdownOpen2"
  },
  {
    customKey: 3,
    options: [
      { title: "Submenu 3", header: true },
      { title: "Submenu 3.1", header: false }
    ],
    name: "dropdownOpen3"
  }
];

function App() {
  const [keysForDropdown, setKeysForDropdown] = useState({});

  useEffect(() => {
    const keys = dropdownConfig.map(dropdown => dropdown.name);
    const object = keys.reduce((acc, curr) => {
      acc[curr] = false;
      return acc;
    }, {});
    setKeysForDropdown({ ...object });
  }, []);

  const _handleToggle = e => {
    setKeysForDropdown({
      ...keysForDropdown,
      [e.target.name]: !keysForDropdown[e.target.name]
    });
  };

  const _handleMouseEnter = e => {
    setKeysForDropdown({
      ...keysForDropdown,
      [e.target.name]: !keysForDropdown[e.target.name]
    });
  };

  const _handleMouseLeave = e => {
    setKeysForDropdown({
      ...keysForDropdown,
      [e.target.name]: !keysForDropdown[e.target.name]
    });
  };

  return (
    <div className="App">
      <Container>
        {keysForDropdown &&
          dropdownConfig.map(dropdown => (
            <CustomDropDown
              {...dropdown}
              key={dropdown.customKey}
              stateKeys={keysForDropdown}
              handleToggle={_handleToggle}
              handleMouseEnter={_handleMouseEnter}
              handleMouseLeave={_handleMouseLeave}
            />
          ))}
      </Container>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

CustomDropdown.js

import React from "react";
import {
  Dropdown,
  DropdownToggle,
  DropdownMenu,
  DropdownItem
} from "reactstrap";

const CustomDropDown = props => {
  const {
    handleMouseEnter,
    handleMouseLeave,
    handleToggle,
    options,
    name,
    stateKeys
  } = props;
  return (
    <div className="dropdown-container">
      <Dropdown
        className="d-inline-block"
        onMouseOver={handleMouseEnter}
        onMouseLeave={handleMouseLeave}
        isOpen={stateKeys[name]}
        toggle={handleToggle}
      >
        <DropdownToggle name={name} caret>
          Dropdown1
        </DropdownToggle>
        <DropdownMenu>
          {options.length &&
            options.map(({ header, title }) => (
              <DropdownItem header={header}>{title}</DropdownItem>
            ))}
        </DropdownMenu>
      </Dropdown>
    </div>
  );
};

export default CustomDropDown;

希望这对你有所帮助!如果有其他问题,请随时提出。

英文:

So basically you were using same state variable for all three dropdowns.

To fix this you need to maintain three different state variables, since you want to have dynamic way you can follow the below approach

Also for reusable approach you can make the Dropdown as a separate component.

You can add more logic if you want, this is the simple way to solve the problem

App.js

import React, { useState, useEffect } from &quot;react&quot;;
import ReactDOM from &quot;react-dom&quot;;
import { Container } from &quot;reactstrap&quot;;
import CustomDropDown from &quot;./CustomDropdown&quot;;
import &quot;bootstrap/dist/css/bootstrap.min.css&quot;;
import &quot;./styles.css&quot;;
const dropdownConfig = [
{
customKey: 1,
options: [
{ title: &quot;Submenu 1&quot;, header: true },
{ title: &quot;Submenu 1.1&quot;, header: false }
],
name: &quot;dropdownOpen1&quot;
},
{
customKey: 2,
options: [
{ title: &quot;Submenu 2&quot;, header: true },
{ title: &quot;Submenu 2.1&quot;, header: false }
],
name: &quot;dropdownOpen2&quot;
},
{
customKey: 3,
options: [
{ title: &quot;Submenu 3&quot;, header: true },
{ title: &quot;Submenu 3.1&quot;, header: false }
],
name: &quot;dropdownOpen3&quot;
}
];
function App() {
const [keysForDropdown, setKeysForDropdown] = useState({});
useEffect(() =&gt; {
const keys = dropdownConfig.map(dropdown =&gt; dropdown.name);
const object = keys.reduce((acc, curr) =&gt; {
acc[curr] = false;
return acc;
}, {});
setKeysForDropdown({ ...object });
}, []);
const _handleToggle = e =&gt; {
setKeysForDropdown({
...keysForDropdown,
[e.target.name]: !keysForDropdown[e.target.name]
});
};
const _handleMouseEnter = e =&gt; {
setKeysForDropdown({
...keysForDropdown,
[e.target.name]: !keysForDropdown[e.target.name]
});
};
const _handleMouseLeave = e =&gt; {
setKeysForDropdown({
...keysForDropdown,
[e.target.name]: !keysForDropdown[e.target.name]
});
};
return (
&lt;div className=&quot;App&quot;&gt;
&lt;Container&gt;
{keysForDropdown &amp;&amp;
dropdownConfig.map(dropdown =&gt; (
&lt;CustomDropDown
{...dropdown}
key={dropdown.customKey}
stateKeys={keysForDropdown}
handleToggle={_handleToggle}
handleMouseEnter={_handleMouseEnter}
handleMouseLeave={_handleMouseLeave}
/&gt;
))}
&lt;/Container&gt;
&lt;/div&gt;
);
}
const rootElement = document.getElementById(&quot;root&quot;);
ReactDOM.render(&lt;App /&gt;, rootElement);

CustomDropdown.js

import React from &quot;react&quot;;
import {
Dropdown,
DropdownToggle,
DropdownMenu,
DropdownItem
} from &quot;reactstrap&quot;;
const CustomDropDown = props =&gt; {
const {
handleMouseEnter,
handleMouseLeave,
handleToggle,
options,
name,
stateKeys
} = props;
return (
&lt;div className=&quot;dropdown-container&quot;&gt;
&lt;Dropdown
className=&quot;d-inline-block&quot;
onMouseOver={handleMouseEnter}
onMouseLeave={handleMouseLeave}
isOpen={stateKeys[name]}
toggle={handleToggle}
&gt;
&lt;DropdownToggle name={name} caret&gt;
Dropdown1
&lt;/DropdownToggle&gt;
&lt;DropdownMenu&gt;
{options.length &amp;&amp;
options.map(({ header, title }) =&gt; (
&lt;DropdownItem header={header}&gt;{title}&lt;/DropdownItem&gt;
))}
&lt;/DropdownMenu&gt;
&lt;/Dropdown&gt;
&lt;/div&gt;
);
};
export default CustomDropDown;

Working codesandbox

huangapple
  • 本文由 发表于 2020年1月3日 15:44:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/59574892.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定