React TypeScript动态渲染组件时获取组件名与导航高亮实现
问题根源
你当前将React.ReactNode类型的JSX元素直接存入state的写法本身就存在设计缺陷,直接访问page.type报TS错误的原因很明确:React.ReactNode是个覆盖范围极广的联合类型,包含字符串、数字、布尔值、React Fragment、Portal等多种不存在type属性的值,TS无法确定你存的page一定是带type字段的React元素,因此会抛出类型错误。
就算你用类型断言强行绕过TS检查,这个方案也无法在生产环境正常运行:构建工具压缩代码时会改写组件的name属性,基于组件名的判断逻辑会直接失效。
最优实现方案
不要在state中存储JSX元素,改为存储当前激活页面的唯一标识,基于标识做组件渲染和导航态判断,完全规避获取组件名的问题,同时做到类型安全、不受代码压缩影响。
实现代码
- 首先定义页面标识枚举,统一管理所有可切换页面:
// 所有可切换页面的唯一标识 enum PageType { Chats = 'chats', Profile = 'profile', // 后续新增页面直接在这里加枚举值即可 }
- 建立页面标识和对应组件的映射关系:
import UserChats from '@/pages/UserChats'; import UserProfile from '@/pages/UserProfile'; const pageComponentMap = { [PageType.Chats]: <UserChats />, [PageType.Profile]: <UserProfile />, };
- state中仅存储当前激活的页面标识,初始值设为默认展示的页面:
const [activePage, setActivePage] = useState<PageType>(PageType.Chats);
- 页面渲染和导航激活判断直接基于
activePage做匹配,逻辑清晰无歧义:
return ( <div className="app-container"> {/* 渲染当前激活的页面组件 */} <main className="content-area"> {pageComponentMap[activePage]} </main> {/* 底部导航栏 */} <nav className="bottom-navbar"> <button className={`nav-btn ${activePage === PageType.Chats ? 'nav-btn--active' : ''}`} onClick={() => setActivePage(PageType.Chats)} > 消息图标 </button> <button className={`nav-btn ${activePage === PageType.Profile ? 'nav-btn--active' : ''}`} onClick={() => setActivePage(PageType.Profile)} > 个人中心图标 </button> </nav> </div> );
你只需要给.nav-btn--active类写对应高亮样式(比如修改图标、文字颜色)即可实现导航激活态的动态切换。
不推荐的临时兼容方案
如果你一定要从已存储的ReactNode中取组件名,必须先通过React内置的isValidElement方法做类型收窄,排除非React元素的类型后再访问属性,但请注意该方案无法兼容生产环境代码压缩,仅适合本地调试使用:
import { isValidElement } from 'react'; let componentName: string | null = null; if (isValidElement(page)) { componentName = typeof page.type === 'string' ? page.type // 原生dom元素直接取type字符串 : (page.type as { displayName?: string; name?: string }).displayName || (page.type as { name?: string }).name; }
内容的提问来源于stack exchange,提问作者José Carlos
相关产品推荐
相关产品推荐

