next.js 无法使用React获取组件名称,Children

4szc88ey  于 2023-11-18  发布在  React
关注(0)|答案(1)|浏览(111)

我使用react和nextjs框架,我尝试用这样的结构构建我自己的javascript组件

<Dropdown>
   <DropdownToggle>Action</DropdownToggle>
   <DropdownMenu>
      <DropdownItem>Menu 1</DropdownItem>
      <DropdownItem>Menu 2</DropdownItem>
   </DropdownMenu>
</Dropdown>

字符串
让我们关注一下子对象(DropdownToggle和DropdownMenu),在子对象组件中,我想在DropdownMenu上传递变量isOpen,在DropdownToggle上传递变量onClick,我想检查子对象是DropdownToggle还是DropdownMenu组件
Dropdown.tsx

export const Dropdown = () => {
   const [dropdownOpen, setDropdownOpen] = useState(false);

   const childrenWithProps = React.Children.map(children, child => {
      // child.type (div or button / html tag) or child.type.name (undefined)
      if (React.isValidElement(child) && child.props?.className?.includes('DropdownToggle')) {
         return React.cloneElement(child, {
           onClick: () => {
             setDropdownOpen(!dropdownOpen)
           },
         });
      }
      if (React.isValidElement(child) && child.props?.className?.includes('DropdownMenu')) {
         return React.cloneElement(child, {
           isOpen: dropdownOpen,
         });
      }
      return child;
   });
   return (
      <div className={styles.dropdown}>
         {childrenWithProps}
      </div>
   )
}


DropdownToggle.tsx

export const DropdownToggle: React.FC<PropsWithChildren<DropdownToggleProp>> = ({onClick, children}) => {
   return (
      <button onClick={onClick}>
        {children}
      </button>
   )
}


DropdownMenu.tsx

export const DropdownMenu: React.FC<PropsWithChildren<DropdownMenuProp>> = ({isOpen, children}) => {
   return (
      <div className={isOpen && 'open'}>
        {children}
      </div>
   )
}


1.我无法使用child.type(返回按钮或div)、child.type.name(返回未定义)、child.type.displayName(返回未定义)获取组件名称,因此我通过className进行检查
1.我在服务器和客户端得到错误:警告:React不识别DOM元素上的isOpen prop。组件DropdownMenu props不被识别,但它直接附加到DOM元素

ckocjqey

ckocjqey1#

这看起来像是一个上下文会更容易的东西。那么你就不需要担心传递 prop 了。
例如,Dropdown组件可以是上下文提供程序

interface DropdownContextValue {
  isOpen: boolean;
  toggle: () => void;
}

export const DropdownContext = createContext<DropdownContextValue>({
  isOpen: false,
  toggle: () => {}
});

// a handy custom hook
export const useDropdown = () => useContext(DropdownContext);

export const Dropdown = ({ children }: PropsWithChildren) => {
  const [isOpen, setIsOpen] = useState(false);

  const toggle = () => {
    setIsOpen((prev) => !prev);
  };

  return (
    <DropdownContext.Provider value={{ isOpen, toggle }}>
      <div className={styles.dropdown}>{children}</div>
    </DropdownContext.Provider>
  );
};

字符串
在您的组件中,您可以使用上下文挂钩

export const DropdownToggle = ({ children }: PropsWithChildren) => {
  const { toggle } = useDropdown();
  return <button onClick={toggle}>{children}</button>;
};

export const DropdownMenu = ({ children }: PropsWithChildren) => {
  const { isOpen } = useDropdown();
  return <div className={isOpen ? "open" : ""}>{children}</div>;
};


的数据

相关问题