如何定位特定项目切换点击使用React Hooks?

问题描述 投票:1回答:2

我有一个导航栏组件,实际信息从CMS中提取。一些导航链接有一个下拉组件onclick,而其他导航链接没有。我很难搞清楚如何使用React Hooks定位特定菜单索引 - 当前onClick,它会立即打开所有下拉菜单,而不是我点击的特定菜单。

支持toggleOpen基于handleDropDownClick事件处理程序传递给样式化组件。

继承我的组成部分。

const NavBar = props => {
 const [links, setLinks] = useState(null);
 const [notFound, setNotFound] = useState(false);
 const [isOpen, setIsOpen] = useState(false);

 const fetchLinks = () => {
   if (props.prismicCtx) {
     // We are using the function to get a document by its uid
     const data = props.prismicCtx.api.query([
       Prismic.Predicates.at('document.tags', [`${config.source}`]),
       Prismic.Predicates.at('document.type', 'navbar'),
     ]);
     data.then(res => {
       const navlinks = res.results[0].data.nav;
       setLinks(navlinks);
     });
   }
   return null;
 };

 const checkForLinks = () => {
   if (props.prismicCtx) {
     fetchLinks(props);
   } else {
     setNotFound(true);
   }
 };

 useEffect(() => {
   checkForLinks();
 });

 const handleDropdownClick = e => {
   e.preventDefault();
   setIsOpen(!isOpen);
 };

 if (links) {
   const linkname = links.map(item => {
     // Check to see if NavItem contains Dropdown Children
     return item.items.length > 1 ? (
       <Fragment>
         <StyledNavBar.NavLink onClick={handleDropdownClick} href={item.primary.link.url}>
           {item.primary.label[0].text}
         </StyledNavBar.NavLink>
         <Dropdown toggleOpen={isOpen}>
           {item.items.map(subitem => {
             return (
               <StyledNavBar.NavLink href={subitem.sub_nav_link.url}>
                 <span>{subitem.sub_nav_link_label[0].text}</span>
               </StyledNavBar.NavLink>
             );
           })}
         </Dropdown>
       </Fragment>
     ) : (
       <StyledNavBar.NavLink href={item.primary.link.url}>
         {item.primary.label[0].text}
       </StyledNavBar.NavLink>
     );
   });
   // Render
   return (
     <StyledNavBar>
       <StyledNavBar.NavContainer wide>
         <StyledNavBar.NavWrapper row center>
           <Logo />
           {linkname}
         </StyledNavBar.NavWrapper>
       </StyledNavBar.NavContainer>
     </StyledNavBar>
   );
 }
 if (notFound) {
   return <NotFound />;
 }
 return <h2>Loading Nav</h2>;
};

export default NavBar;
reactjs event-handling styled-components react-hooks
2个回答
1
投票

你的问题是你的状态只处理一个布尔值(是否打开),但实际上你需要多个布尔值(每个菜单项有一个“打开或不打开”)。你可以尝试这样的事情:

const [isOpen, setIsOpen] = useState({});

const handleDropdownClick = e => {
    e.preventDefault();
    const currentID = e.currentTarget.id;
    const newIsOpenState = isOpen[id] = !isOpen[id];
    setIsOpen(newIsOpenState);
};

最后在你的HTML中:

const linkname = links.map((item, index) => {
    // Check to see if NavItem contains Dropdown Children
    return item.items.length > 1 ? (
        <Fragment>
            <StyledNavBar.NavLink id={index} onClick={handleDropdownClick} href={item.primary.link.url}>
               {item.primary.label[0].text}
            </StyledNavBar.NavLink>
            <Dropdown toggleOpen={isOpen[index]}>

    // ... rest of your component

请注意.map函数中的新索引变量,该变量用于标识要单击的菜单项。

更新:

我失踪的一点是初始化,正如@MattYao在另一个答案中提到的那样。在您的加载数据中,执行以下操作:

data.then(res => {
    const navlinks = res.results[0].data.nav;
    setLinks(navlinks);
    setIsOpen(navlinks.map((link, index) => {index: false}));
});

与你的问题无关,但你可能想要考虑skipping effects并包括key到你的.map


0
投票

我可以看到前两个useState钩子正在按预期工作。问题是你的第3个useState()钩子。

问题很明显,你是通过元素列表引用相同的状态变量isOpen,因此它们都具有相同的状态。为了解决这些问题,我建议采用以下方法:

  1. 您不需要使用isOpen的一个值,而是需要使用数组或Map初始化状态,以便您可以引用每个个体: const initialOpenState = [] // or using ES6 Map - new Map([]);
  2. 在fetchLink函数回调中,将isOpen状态数组值初始化为false。所以你可以把它放在这里: data.then(res => { const navlinks = res.results[0].data.nav; setLinks(navlinks); // init your isOpen state here navlinks.forEach(link => isOpen.push({ linkId: link.id, value: false })) //I suppose you can get an id or similar identifers });
  3. 在handleClick函数中,您必须将链接对象作为目标并将其设置为true,而不是将所有内容都设置为true。您可能需要使用.find()来找到您单击的链接: handleClick = e => { const currentOpenState = state; const clickedLink = e.target.value // use your own identifier currentOpenState[clickedLink].value = !currentOpenState[clickedLink].value; setIsOpen(currentOpenState); }
  4. 更新组件,以便使用正确的isOpen状态: <Dropdown toggleOpen={isOpen[item].value}> // replace this value {item.items.map(subitem => { return ( <StyledNavBar.NavLink href={subitem.sub_nav_link.url}> <span>{subitem.sub_nav_link_label[0].text}</span> </StyledNavBar.NavLink> ); })} </Dropdown>

如果您只是复制和粘贴,上面的代码可能不适合您。但它应该让你知道事情应该如何协同工作。

© www.soinside.com 2019 - 2024. All rights reserved.