如何在父级styled-component中获取子组件的isOpen属性并应用对应样式
你的写法存在3个核心问题
StyledTopBarProps未定义isOpen字段,也没有从上层接收、传递该属性,样式函数无法拿到isOpen值- styled-components 的
variant配置仅支持静态样式值,你在样式对象内嵌套箭头函数的写法不被支持,函数不会被执行,只会被序列化为字符串 - React默认是单向数据流,父组件无法直接读取子组件的内部状态,如果
isOpen是NavIcon的内部状态,TopBar原本就拿不到这个值
可行解决方案
方案1:状态提升(符合React单向数据流原则)
如果确实需要父组件统一控制子元素样式,把isOpen状态从NavIcon内部提到上层维护即可:
- 先更新类型定义,新增
isOpen字段
interface TopBarProps { // 保留原有其他属性 isOpen?: boolean; } interface StyledTopBarProps extends SpaceProps, LayoutProps { mode: TopBarProps['mode']; iconMode: TopBarProps['iconMode']; sticky?: boolean; isOpen?: boolean; // 新增字段 }
- 改造TopBar组件,接收并传递
isOpen给StyledTopBar
const TopBar: FunctionComponent<TopBarProps> = ({ mode, iconMode, justified, sticky, children, isOpen, // 新增接收 }: TopBarProps) => { return ( <StyledTopBar as={justified ? 'div' : 'header'} px={justified ? [-4, -4, 0] : [4, 4, 6, 6]} height="size11" mode={mode} iconMode={iconMode} sticky={sticky} isOpen={isOpen} // 传递给样式组件 > <TopBarWrapper justified={justified}>{children}</TopBarWrapper> </StyledTopBar> ); };
- 调整StyledTopBar的样式写法,不要在variant里嵌套函数,把动态逻辑提到外层:
const StyledTopBar = styled('header').withConfig({ shouldForwardProp, })<StyledTopBarProps>` /* 保留原有其他样式 */ ${({ theme, mode, iconMode, isOpen }) => css` ${variant({ prop: 'iconMode', variants: { light: { color: 'text.text1Inverse', span: { color: 'text.text1Inverse', '&:hover, &:focus, &:focus-within, &:active': { borderColor: 'text.text1Inverse', background: 'transparent', }, }, }, dark: { color: 'text.link', span: { color: 'text.link', }, }, }, })} /* 单独处理span的动态borderColor */ ${iconMode === 'light' && ` span { border-color: ${getIconBorderColor(theme.colors, mode, isOpen)}; } `} `} ${variant({ prop: 'sticky', variants: { true: { position: 'fixed', zIndex: 'header', }, }, })} `;
- 使用TopBar时,把
isOpen状态同时传给TopBar和内部的NavIcon:
const [isNavOpen, setIsNavOpen] = useState(false); return ( <TopBar mode="light" iconMode="light" isOpen={isNavOpen}> <StyledNavIcon mode="light" isOpen={isNavOpen} onClick={() => setIsNavOpen(!isNavOpen)} /> {/* 其他子组件 */} </TopBar> )
方案2:子组件自行适配样式(更解耦,优先推荐)
如果没有特殊的全局控制需求,完全不用修改TopBar代码,直接在StyledNavIcon里补全自身样式即可,符合组件职责分离原则:
const StyledNavIcon = styled('span').withConfig({ shouldForwardProp, })<StyledNavIconProps>` cursor: pointer; border-color: ${(props) => getBorderColor(props.theme.colors, props.mode, props.isOpen)}; /* 自行处理对应模式下的交互样式 */ ${props => props.mode === 'light' && css` &:hover, &:focus, &:focus-within, &:active { border-color: ${props.theme.colors.text.text1Inverse}; background: transparent; } `} `;
内容的提问来源于stack exchange,提问作者Toni Michel Caubet
相关产品推荐
相关产品推荐

