Reactjs 使用图标选择多个项目

Reactjs 使用图标选择多个项目,reactjs,react-hooks,Reactjs,React Hooks,我正在尝试实现一个具有许多项的popover,用户可以在其中多选择这些项。当用户单击某个项目时,右侧会显示一个字体图标 用户可以选择多个项目,并在右侧显示一个图标以显示已选中。单击时,此图标将切换。我的问题是,我的事件处理程序绑定到所有项目,每当我单击一个项目时,都会检查所有项目 我是个新手,不会勾引和反应。我还尝试在数组中分配所选项目的Id。它不会追加 const SettingsComponent = (props) => { const urlStofTyper = stofType

我正在尝试实现一个具有许多项的popover,用户可以在其中多选择这些项。当用户单击某个项目时,右侧会显示一个字体图标

用户可以选择多个项目,并在右侧显示一个图标以显示已选中。单击时,此图标将切换。我的问题是,我的事件处理程序绑定到所有项目,每当我单击一个项目时,都会检查所有项目

我是个新手,不会勾引和反应。我还尝试在数组中分配所选项目的Id。它不会追加

const SettingsComponent = (props) => {
const urlStofTyper = stofTyperUrl; 
const stofTyper = [];
const [isPopoverOpen, setPopoverOpen] = useState(false);

const [isItemChecked, setItemChecked] = useState(false);

const [error, setError] = useState(null);
const [loading, setLoading] = useState(null);
const [stoftype, setStoftyper] = useState({ DataList: [] });

const toggle = () => setPopoverOpen(!isPopoverOpen);

const sectionClicked = (e) => {
setItemChecked(!isItemChecked);
let secId = e.target.parentNode.getAttribute("data-section");   
if (!isItemChecked) {
    stofTyper.push(secId);
   } else {
    stofTyper.filter((sec) => sec == secId);
  }
};

useEffect(() => {
fetchStoftyper({ setError, setLoading, setStoftyper });
}, []);

const fetchStoftyper = async ({ setError, setLoading, setStoftyper }) => {
try {
    setLoading(true);
    const response = await Axios(urlStofTyper);
    const allStofs = response.data;
    setLoading(false);
    setStoftyper(allStofs);
  } catch (error) {
    setLoading(false);
    setError(error);
  }
};

return (
<React.Fragment>
  <div className='list-header-icons__fontawesome-icon' id='PopoverClick'>
    <FontAwesomeIcon icon={faCog} />
  </div>
  <Popover
    isOpen={isPopoverOpen}
    placement='bottom'
    toggle={toggle}
    target='PopoverClick'>
    <PopoverHeader>formatter</PopoverHeader>
    <div className='popover-body'>
      <ul className='individual-col--my-dropdown-menu-settings'>
        {stoftype.DataList.map((item) => (
          <li key={item.Id} className='section-items'>
            <a
              onClick={sectionClicked}                 
              className='dropdown-item'                 

              data-section={item.Sections[0].SectionId}
              data-format={
                item.Formats.length > 0
                  ? item.Formats[0].FormatId
                  : ""
              }
              aria-selected='false'>
              <span className='formatter-name'>
                {item.Name}
              </span>
              {isItemChecked && (
                <span className='formatter-check-icon'>
                  <FontAwesomeIcon icon={faCheck} size='lg' />
                </span>
              )}
            </a>
          </li>
        ))}
      </ul>
    </div>
  </Popover>
</React.Fragment>
);
const settings组件=(道具)=>{
常量urlStofTyper=stoftyperl;
常量stofTyper=[];
const[isPopoverOpen,setPopoverOpen]=useState(false);
const[isItemChecked,setItemChecked]=useState(false);
const[error,setError]=useState(null);
const[loading,setLoading]=useState(null);
const[stoftype,setStoftyper]=useState({DataList:[]});
const toggle=()=>setPopoOverOpen(!isPoOverOpen);
const sectionClicked=(e)=>{
setItemChecked(!isItemChecked);
设secId=e.target.parentNode.getAttribute(“数据段”);
如果(!isItemChecked){
stofTyper.push(secId);
}否则{
stofTyper.filter((sec)=>sec==secId);
}
};
useffect(()=>{
fetchStoftyper({setError,setLoading,setToftyper});
}, []);
const fetchStoftyper=async({setError,setLoading,setStoftyper})=>{
试一试{
设置加载(真);
常量响应=等待Axios(urlStofTyper);
const allStofs=response.data;
设置加载(假);
设置打字机(所有STOFS);
}捕获(错误){
设置加载(假);
设置错误(错误);
}
};
返回(
格式化程序
    {stoftype.DataList.map((项)=>(
  • 0 ?项。格式[0]。格式ID : "" } aria selected='false'> {item.Name} {isItemChecked&&( )}
  • ))}
);
现在,您正在使用一个布尔变量来检查图标是否应该显示,它将不起作用,因为
数据列表中的每个项目都应该有自己的单独指示器

一种可能的解决方案是为此使用
newmap()
,并将
item.id
存储为索引,将
true/false
存储为值,因此您选择的状态如下:

Map(3) {1 => true, 2 => true, 3 => false}
之后,您可以检查是否应显示图标,如下所示:

!!selected.get(item.id) 
如果哈希表中的值为true,则返回true;如果为false或根本不存在,则返回false。这应该足以实现您要求的功能


对于真实的示例,您可以查看它们显示了如何使用此技术实现多重选择。希望有帮助。

最后,我有一个解决我自己问题的办法。尽管如此,我并不需要上述解决方案,但我认为尝试解决它将是一个很好的实践。Popover不相关,因为它仅用作包装器。下面的解决方案仍然可以放置在Popover中

CodeSandBox链接:使用类组件,我将尝试尽快使用钩子重新编写

此解决方案依赖于Bootstrap 4和Fontsome

import React, { Component } from "react";
import Cars from "./DataSeed";

class DropDownWithSelect extends Component {
  constructor(props) {
    super(props);

    this.toggleDropdown = this.toggleDropdown.bind(this);

    this.state = {
      isDropDownOpen: false,
      idsOfItemClicked: []
    };
  }

  toggleDropdown = evt => {
    this.setState({
      isDropDownOpen: !this.state.isDropDownOpen
    });
  };

  toggleItemClicked = id => {
    this.setState(state => {
      const idsOfItemClicked = state.idsOfItemClicked.includes(id)
        ? state.idsOfItemClicked.filter(x => x !== id)
        : [...state.idsOfItemClicked, id];

      return {
        idsOfItemClicked
      };
    });
  };

  render() {
    return (
      <div className="dropdown">
        <button
          onClick={this.toggleDropdown}
          className="btn btn-secondary dropdown-toggle"
          type="button"
          id="dropdownMenuButton"
          data-toggle="dropdown"
          aria-haspopup="true"
          aria-expanded="false"
        >
          Dropdown button
        </button>
        {this.state.isDropDownOpen && (
          <div
            className="dropdown-menu show"
            aria-labelledby="dropdownMenuButton"
          >
            {Cars.map(x => {
              return (
                <div
                  key={x.id}
                  onClick={() => this.toggleItemClicked(x.id)}
                  className="dropdown-item d-inline-flex justify-content-between"
                >
                  <span className="d-flex"> {x.name} </span>
                  <span className="d-flex align-self-center">
                    {this.state.idsOfItemClicked.includes(x.id) && (
                      <i className="fa fa-times" aria-hidden="true" />
                    )}
                  </span>
                </div>
              );
            })}
          </div>
        )}
      </div>
    );
  }
}
export default DropDownWithSelect;

你好,尼古拉,谢谢你花时间和精力。我会调查一下,然后回来。
    const cars = [
  {
    id: 1,
    name: "BMW",
    cost: 450000
  },
  {
    id: 2,
    name: "Audi",
    cost: 430000
  },
  {
    id: 3,
    name: "Mercedes",
    cost: 430000
  }
];

export default cars;