警告:react-modal:未定义应用程序元素。请使用`Modal.setAppElement(el)`或设置`appElement = {el}`。

53

我该如何解决在React应用程序中使用react-modal包时控制台中出现的以下警告:

Warning: react-modal:未定义App元素。 请使用Modal.setAppElement(el)或设置appElement={el}

我一直无法弄清楚el应该是什么。

背景: 在我的App.js根组件文件中:

...
import Modal from 'react-modal';
...
class App extends Component {
  ...
  render(){
    ...  
    <Modal
      className="modal"
      overlayClassName="overlay"
      isOpen={foodModalOpen}
      onRequestClose={this.closeFoodModal}
      contentLabel="Modal"
    >
    ...
  }
}

其中...表示未显示的代码。

一切都运行良好,但当模态框打开时,我的控制台会出现以下警告:

index.js:2177 警告:react-modal:未定义应用程序元素。请使用Modal.setAppElement(el)或设置appElement={el}。这是必需的,以便屏幕阅读器在打开模态框时不会看到主内容。虽然不建议,但您可以通过设置ariaHideApp={false}来选择退出。

react-modal文档中,我能找到的仅有以下内容:

应用程序元素
应用程序元素允许您指定应该隐藏的应用程序部分(通过aria-hidden),以防止辅助技术(如屏幕阅读器)阅读模态框内容之外的内容。

如果您正在进行服务器端渲染,则应使用此属性。

它可以通过以下方式指定:

DOM元素
Modal.setAppElement(appElement);
查询选择器-如果传入类,则使用找到的第一个元素。
Modal.setAppElement('#your-app-element');

不幸的是,这没有帮助!我无法弄清楚el应该表示什么。

以下是我尝试添加到我的模态框组件中的许多属性变化:

`appElement={el}`,  
`appElement="root"` where `root` is the id that my App component is injected into   
`appElement={'root'}`   
`appElement="div"`,   
`appElement={<div>}`,   
`appElement={"div"}`  

我还尝试过在src/index.js中调用Modal.setAppElement('root');,其中root是我的App组件注入的根元素,而index.js是我这样做的地方。


1
Sheryl的回答是正确的 - 但是为了让你知道,“el”通常指的是引用,是“element”的缩写。 - Wills Manley
13个回答

57
< p >将ariaHideApp={false}添加到Modal属性中。

这应该可以工作:

<Modal isOpen={!!props.selectedOption}
    onRequestClose={props.clearSelectedOption}
    ariaHideApp={false}
    contentLabel="Selected Option"
    >
</Modal>

10
官方文档中写道:不建议这样做,但您可以通过设置 ariaHideApp={false} 来选择退出。 - Frederiko Cesar
6
最好按照指示去做,这样可以避免警告所提到的可访问性问题。 - Michael Oryl

34

react-modal问题#133中提供了一些解决方案:

问题出在这里: 取决于何时评估react-modal@1.6.5:/lib/helpers/ariaAppHider.js#L1:

  • document.body还不存在,它将解析为undefined || null
  • 如果使用null调用Modal.setAppElement()或未调用Modal.setAppElement()并将<script />放置在<head />上(与上面相同)。
  • 如果使用不匹配任何结果的selector进行调用,可能也会发生这种情况。

解决方案:

浏览器渲染:

@yachaka代码片段通过在放置<Modal />之前定义元素来防止此行为:

componentWillMount() {
    Modal.setAppElement('body');
}

@ungoldman的回答,如果你不想依赖于`setAppElement':

将捆绑的应用程序 JS 注入到<body>中而不是<head>中。
尽管理想情况下,react-modal应该等待DOM加载后再尝试附加到document.body

服务器端:

如果在服务器端呈现,则必须提供document.body,然后才能要求模态脚本(在这种情况下使用setAppElement()可能更可取)。


更新React文档已经更新,包括上述信息,因此现在对遇到此问题的用户应该更清晰。
React-Modal issue #567:将来自上面链接的问题#133的信息添加到文档中。


如果模态框仅在组件内使用,是否可以将其挂载,以使覆盖层仅覆盖该组件 - 而不是该组件的父级/祖先? 我尝试过了,但似乎没起作用,它会重新覆盖整个屏幕。 - joedotnot
2
现在componentWillMount()已被弃用,有一个新的解决方案会很有用。但我找不到一个。 - Jamie McLaughlin
在函数组件中,useEffect(..., [])可以完成工作。 - undefined

20

只需在您的模态框中像这样包含appElement={document.getElementById('app')}即可

<Modal
className="modal"
appElement={document.getElementById('app')}
>

如果应用程序是在index.html中作为React加载的中心,则它将100%正常工作。


由于 getElementById 可能为空,您可能需要一个类型安全的备用方案。 - Mo Beigi
5
@MoBeigi appElement={document.getElementById('root') || undefined} 似乎已经足够。 - runeks

13

这是我的TypeScript Modal组件,它包装了react-modal v3.8.1版本:

import React from 'react'
import ReactModal from 'react-modal'

interface Props {
  isOpen: boolean
  ariaLabel?: string
}

const Modal: React.FC<Props> = ({
  children,
  ariaLabel = 'Alert Modal',
  isOpen,
}) => (
  <ReactModal
    appElement={document.getElementById('root') as HTMLElement}
    ariaHideApp={process.env.NODE_ENV !== 'test'}
    isOpen={isOpen}
    contentLabel={ariaLabel}
    testId="modal-content"
  >
    {children}
  </ReactModal>
)

export default Modal

组件中使用 state = { isOpen: true }

<Modal isOpen={this.state.isOpen}>
  <p>
    Modal Content here…
  </p>
  <button onClick={() => { this.setState({ isOpen: false }) }}>Okay</button>
</Modal>

它也适用于React TypeScript项目。因此,我点了赞。 - Goran_Ilic_Ilke
对于使用Next.js + Typescript的情况,使用<Modal ... appElement={document.getElementById('__next') as HTMLElement} ... />。 - undefined

8

如果在运行测试时(我们使用Jest),出现Warning: react-modal: App element is not defined...错误,您可以通过将以下内容添加到测试文件中来抑制警告:

import ReactModal from 'react-modal';
ReactModal.setAppElement('*'); // suppresses modal-related test warnings.

1
感觉很不爽,希望我能找出正确的选择器并传递进去让它正常工作。但目前为止,这至少可以抑制我的测试中的警告,所以我很高兴! - dmikester1
1
更新我的先前评论。一旦我解决了那个问题并且能够看到DOM树的输出,我发现在树的顶部有一个<body>标签。所以我尝试将其放入其中而不是使用*,结果成功了! - dmikester1

4
最简单的解决方案是添加
appElement={document.getElementById("hereIsYourRootElementId")}它让react-modal知道你的根元素在哪里。

4

只需要加入以下代码
Modal.setAppElement('#root')

这个代码将会解决警告,因为根元素在公共文件夹的index.html里。


3

供参考,如果你正在进行SSR,请使用以下代码来防止服务器端错误:

if (typeof(window) !== 'undefined') {
    ReactModal.setAppElement('body')
}

您可以将此代码放在componentDidMount()中,无论何时您使用模态框,或者您可以将其放在自定义模态框组件中,这样更加整洁和DRY。

react-modal 已经在上游修复,所以这不再是一个问题。 - Nathaniel Hill
2
不是这样的,我已经更新了模块,但仍然收到这个警告。 - Peter

3
对于Nextjs,我认为您可以通过在模态组件外部添加以下内容来解决此问题,可能是在组件声明之前的顶部。
Modal.setAppElement('#__next')

2
你需要在你的根元素 ID 前面添加 #。
import React from 'react';
import Modal from 'react-modal';


Modal.setAppElement('#root');

const OptionModal = (props) => (
  <Modal
    isOpen={!!props.selectedOption}
    contentLabel='this is the selected option'
  >
    <h3>Selected Option</h3>
    {props.selectedOption && <p>{props.selectedOption}</p>}
    <button onClick = {props.handleCloseOptionModal}>Close</button>
  </Modal>
);

export default OptionModal;

这是参考链接: http://reactcommunity.org/react-modal/accessibility/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接