React:HTML 详细信息在开始打开时无法控制地切换

Posted

技术标签:

【中文标题】React:HTML 详细信息在开始打开时无法控制地切换【英文标题】:React: HTML Details toggles uncontrollably when starts open 【发布时间】:2020-03-15 11:27:48 【问题描述】:

我正在尝试使用 html <details> 标记来创建一个简单的可扩展部分,该部分使用语义 html 与 React 相结合。

<details><summary></summary></details> 行为开箱即用效果很好,对于使用 IE 的 1-2% 的用户来说,这些用户没有了解内容的显示隐藏特性,这真的不是结束暂时始终显示内容的世界。

我的问题出现在使用 React 挂钩来保持 <details> 面板是打开还是关闭时。 React 组件的基本布局如下:

const DetailsComponent = (startOpen) => 
  const [open, toggleOpen] = useState(startOpen);

  return (
    <details onToggle=() => toggleOpen(!open) open=open>
      <summary>Summary</summary>
      <p>Hidden content hidden content hidden content</p>
    </details>
  );
;

我需要使用onToggle 事件的原因是更新open 状态变量以在我的真实示例中触发其他一些javascript。我使用startOpen 属性来决定是否在页面上呈现详细信息窗格是打开还是关闭。

当我将组件用作&lt;DetailsComponent startOpen= false /&gt; 时,会发生预期的行为。

但是,当我想在加载时打开窗格 (&lt;DetailsComponent startOpen= true /&gt;) 开始时,我可以看到窗格打开和关闭的速度非常非常快,并且永远一遍又一遍。

【问题讨论】:

【参考方案1】:

我认为你应该使用 prevState

<details onToggle=() => toggleOpen(prevOpen => !prevOpen ) open=open>

【讨论】:

谢谢你,不幸的是,这对我不起作用,但我认为通常更好的做法是在切换打开中明确使用以前的状态,因为它更明确地使用 Hooks。 【参考方案2】:

&lt;details&gt; HTML 元素不需要用js控制,因为它已经具备了打开和关闭的功能。当您传递open 属性并在ontoggle 事件中更改它时,您将创建一个无限的事件循环,因为元素被切换,然后打开状态更改,从而触发触发ontoggle 事件的元素等等。 .. 您唯一需要做的就是传递初始打开状态。

const DetailsComponent = (startOpen) => 
  return (
    <details open=startOpen>
      <summary>Summary</summary>
      <p>Hidden content hidden content hidden content</p>
    </details>
  );
;

【讨论】:

感谢您的回答,不幸的是,我声明我需要一种方法来跟踪组件内其他逻辑的详细打开/关闭状态。但你是对的,details 组件开箱即用,效果很好! 这解决了我的问题,谢谢:)【参考方案3】:

似乎onToggle 在挂载之前被调用,这会导致它在打开的情况下出现无限循环。因为这会触发一个新的切换事件。

避免这种情况的一种方法是检查details 标签是否已安装,并且仅在安装后才切换。这样你就忽略了第一个切换事件。

const DetailsComponent = ( startOpen ) => 
  const [open, toggleOpen] = useState(startOpen);
  const [isMounted, setMount] = useState(false);

  useEffect(() => 
    setMount(true);
  , []);

  return (
    <details onToggle=() => isMounted && toggleOpen(!open) open=open>
      <summary>Summary</summary>
      <p>Hidden content hidden content hidden content</p>
    </details>
  );
;

您可以在 Codesandbox 中找到工作演示。

【讨论】:

这对我来说是一个很好的解决方案,不确定它是否对元素来说太过分了,但这肯定会在代码审查中出现!【参考方案4】:

我遇到了同样的问题。我最终发现我可以通过处理onToggle 来监控当前状态,而不是使用它来设置open 属性。

export default ( defaultOpen, summary, children : DetailsProps): JSX.Element => 
  const [expanded, setExpanded] = useState(defaultOpen || false);

  return (
    <details open=defaultOpen onToggle=e => setExpanded((e.currentTarget as HTMLDetailsElement).open)>
      <summary>
        expanded ? <ExpandedIcon /> : <CollapsedIcon />
        summary
      </summary>
      children
    </details>
  );
;

因为defaultOpen不改变它不会导致DOM更新,所以HTML控件仍然负责它的状态。

【讨论】:

以上是关于React:HTML 详细信息在开始打开时无法控制地切换的主要内容,如果未能解决你的问题,请参考以下文章

键盘打开时TextInput不可见Expo React Native

React Native, IOS Simulator 打开模拟器时出错。查看地铁日志以获取详细信息

Show Segue from 按钮打开时没有导航控制器

从 Documents 目录在 UIWebview 中打开时,ios-css 和 js 无法在 html 文件中链接

React-responsive-modal:模式打开时更改背景颜色

[React Native][IOS] 应用被通知打开时如何捕捉事件