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

为何同样式Container与原生div包裹单选按钮时键盘导航表现不同

问题描述
  • 预期效果:给单选按钮组添加宽度为200px的外层包裹容器,同时保留默认键盘导航行为:通过左右方向键即可在同组单选按钮间切换选项。
  • 异常表现:
    • 使用内部定义的自定义Container组件包裹单选组时,仅能完成一次选项切换,之后键盘导航完全失效,无法继续切换。自定义组件代码如下:
      const Container = ({ children }) => (
        <div style={{ width: "200px" }}>{children}</div>
      );
      
    • 直接使用原生<div style={{ width: "200px"}}>作为包裹元素时,键盘导航可正常运行。
  • 排查疑点:通过开发者工具检查两种写法最终渲染的DOM结构、样式、语义完全一致,无法定位自定义组件导致功能异常的原因。
问题根因

核心问题是自定义Container组件的定义位置错误:
你将Container组件写在了RadioButtonExample函数组件的内部,每次组件因状态更新触发重渲染时,Container都会生成全新的函数引用。React的diff逻辑判定前后两次渲染的组件类型完全不同,会直接卸载Container下的所有旧DOM节点(包含全部单选按钮),重新挂载一整套全新的DOM元素。
第一次按方向键切换选项时,setValue触发组件重渲染,旧的单选按钮DOM被销毁,新挂载的单选按钮丢失了原有的焦点状态、单选组键盘导航上下文,因此无法继续响应方向键操作。
而直接书写原生<div>时,div是React内置的原生DOM类型,引用永远保持稳定,React只会更新DOM属性,不会卸载重挂整个子树,单选按钮的焦点和导航状态会完整保留,因此功能正常。

修复方案

二选一即可:

  • 方案1:将Container组件移到RadioButtonExample组件外部定义,保证组件引用在每次渲染时保持稳定,避免React误判为新组件触发整棵子树重挂。参考代码:
    import { Stack, RadioButton } from "@shopify/polaris";
    import { useState, useCallback } from "react";
    
    // 移到组件外层定义,引用稳定
    const Container = ({ children }) => (
      <div style={{ width: "200px" }}>{children}</div>
    );
    
    function RadioButtonExample() {
      const [value, setValue] = useState("disabled");
    
      const handleChange = useCallback(
        (_checked, newValue) => setValue(newValue),
        []
      );
    
      return (
        <Container>
          <Stack vertical>
            <RadioButton
              label="Accounts are disabled"
              helpText="Customers will only be able to check out as guests."
              checked={value === "disabled"}
              id="disabled"
              name="accounts"
              onChange={handleChange}
            />
            <RadioButton
              label="Accounts are optional"
              helpText="Customers will be able to check out with a customer account or as a guest."
              id="optional"
              name="accounts"
              checked={value === "optional"}
              onChange={handleChange}
            />
          </Stack>
        </Container>
      );
    }
    
    export default RadioButtonExample;
    
  • 方案2:如果Container组件没有复用需求,直接使用原生div包裹单选组即可,减少不必要的组件嵌套。

内容的提问来源于stack exchange,提问作者Judoboy Alex

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 22:18:22