You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React点符号组件传值:如何将Dropdown.Title的openDropdown传给Menu?

解决方案:通过React Context共享Dropdown组件状态

当前Dropdown.Title的状态仅局限于自身,同级的Dropdown.Menu无法直接获取该状态。我们可以将状态提升到共同的父组件Dropdown中,结合React Context实现子组件间的状态共享,既能保留点符号的组件写法,又无需在外部使用时额外维护状态逻辑。

1. 创建状态管理的Context文件 (openDropdown.tsx)

该文件负责定义Context、管理状态,并提供供子组件调用的Hook:

import { createContext, useContext, useState, ReactNode } from 'react';

// 定义Context的类型约束
type DropdownContextType = {
  open: boolean;
  toggle: () => void;
};

// 创建Context,默认值用于类型提示
const DropdownContext = createContext<DropdownContextType | undefined>(undefined);

// 自定义Hook,简化Context的获取并做合法性校验
export const useDropdown = () => {
  const context = useContext(DropdownContext);
  if (!context) {
    throw new Error('useDropdown 必须在 DropdownProvider 内部使用');
  }
  return context;
};

// Provider组件,封装状态逻辑
export const DropdownProvider = ({ children }: { children: ReactNode }) => {
  const [open, setOpen] = useState(false);
  
  const toggle = () => {
    setOpen(prev => !prev);
  };

  return (
    <DropdownContext.Provider value={{ open, toggle }}>
      {children}
    </DropdownContext.Provider>
  );
};

2. 改造主Dropdown组件

让主组件包裹DropdownProvider,确保内部所有子组件都能访问到Context:

import { DropdownProvider } from './openDropdown';
import DropdownTitle from './DropdownTitle';
import DropdownMenu from './DropdownMenu';
import DropdownItem from './DropdownItem';
import DropdownDivider from './DropdownDivider';

const Dropdown = ({ children, className }: { children: ReactNode; className?: string }) => {
  return (
    <div className={className}>
      <DropdownProvider>
        {children}
      </DropdownProvider>
    </div>
  );
};

// 挂载子组件,保持点符号调用的写法
Dropdown.Title = DropdownTitle;
Dropdown.Menu = DropdownMenu;
Dropdown.Item = DropdownItem;
Dropdown.Divider = DropdownDivider;

export default Dropdown;

3. 修改Dropdown.Title组件

移除自身的状态,直接从Context获取切换方法:

import { useDropdown } from './openDropdown';

const DropdownTitle = ({ children, className }: { children: ReactNode; className?: string }) => {
  const { toggle } = useDropdown();

  return (
    <button 
      type="button" 
      onClick={toggle}
      className={className}
    >
      {children}
    </button>
  );
};

export default DropdownTitle;

4. 修改Dropdown.Menu组件

从Context获取状态,控制菜单的显示隐藏:

import { useDropdown } from './openDropdown';

const DropdownMenu = ({ children, align, className }: { children: ReactNode; align?: string; className?: string }) => {
  const { open } = useDropdown();
  
  // 示例:根据状态和align属性拼接样式类
  const menuClasses = `${className || ''} ${align === 'end' ? 'justify-end' : ''} ${open ? 'block' : 'hidden'}`;

  return (
    <div className={menuClasses}>
      {children}
    </div>
  );
};

export default DropdownMenu;

最终使用方式

和你原本的写法完全一致,无需额外处理状态逻辑:

<Dropdown className="float-right">
  <Dropdown.Title>Open menu</Dropdown.Title>
  <Dropdown.Menu align="end">
    <Dropdown.Item className="hello mate" href="/dashboard">
      Dashboard
    </Dropdown.Item>
    <Dropdown.Item className="hello mate" href="/settings">
      Settings
    </Dropdown.Item>
    <Dropdown.Divider />
    <Dropdown.Item className="hello mate" onClick={signOut}>
      Sign out
    </Dropdown.Item>
  </Dropdown.Menu>
</Dropdown>

内容的提问来源于stack exchange,提问作者Mo.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 04:16:27