无法使Popover显示在对话框中的正确位置

时间:2019-10-21 19:48:06

标签: reactjs material-ui

我有一个对话框,还有一个ListItem,当您单击它时,会显示一个Popover进入编辑模式。这在使用Modal的MUI的较旧版本中有效,但是由于无法使用最新版本,因此我尝试使用Popover。我试图在CodeSandox上做一个简单的例子,但是可行。发生的情况是Popover始终位于页面的左上方,而不是ListItem。

我已经将代码简化为Dialog中的简单Button和Popover,但仍然存在相同的问题,并且对接下来的尝试没有任何想法。我在控制台中看到的错误是

[Warning] Material-UI: the `anchorEl` prop provided to the component is invalid.
The anchor element should be part of the document layout.
Make sure the element is present in the document or that it's not display none.

单击该项目时,就像示例中一样,执行event.currentTarget,这就是console.log的外观。

[Log] <button class="MuiButtonBase-root MuiButton-root MuiButton-text" tabindex="0" type="button"> (main.chunk.js, line 26437)
<span class="MuiButton-label">Click Me</span>
<span class="MuiTouchRipple-root">
<span class="MuiTouchRipple-ripple MuiTouchRipple-rippleVisible" style="width: 117.2006825918689px; height: 117.2006825918689px; top: -34.60034129593445px; left: -25.60034129593445px;">
<span class="MuiTouchRipple-child MuiTouchRipple-childLeaving"></span>
</span>
</span>
</button>

我什至尝试在Dialog中执行disablePortal并没有解决问题。我还尝试使用ref来修复anchorEl警告,但仍相对于页面而不是元素显示。有什么想法吗?

4 个答案:

答案 0 :(得分:7)

对于使用Material UI遇到此问题的任何人,您都可以做几件事。

一种方法是确保如果您有多个嵌套的功能组件,则在保存弹出窗口的特定功能组件内定义弹出窗口的anchorEl / click处理程序。如果您嵌套了功能组件,而父组件拥有该状态,则它将在每次状态更改时重新呈现子级,这可以重置anchorEl参考。

第二-React.memo可以防止在功能组件上不必要的重新渲染(仅在prop不变的情况下才起作用,但仍应在子组件中获得性能上的好处)。

答案 1 :(得分:1)

  1. 检查是否有任何display: none;风格

  2. 可能anchorEl用于多个嵌套功能组件问题

  3. 尝试使用备忘录概念来防止组件重新提交

答案 2 :(得分:0)

由于它的含义,也可能会出现此错误-您可能正在尝试将具有display: none样式的元素用作组件的achorEl,但不支持该元素作为计算该元素的基础逻辑锚元素的位置需要使其在屏幕上可见。

答案 3 :(得分:0)

我嵌套了元素,这就是我在不做任何额外工作的情况下解决这个问题的方法。

所以我的主要功能组件只是返回这样的内容

FROM php:7.4-fpm

RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") \
    && architecture=$(case $(uname -m) in i386 | i686 | x86) echo "i386" ;; x86_64 | amd64) echo "amd64" ;; aarch64 | arm64 | armv8) echo "arm64" ;; *) echo "amd64" ;; esac) \
    && curl -A "Docker" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/$architecture/$version \
    && mkdir -p /tmp/blackfire \
    && tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \
    && mv /tmp/blackfire/blackfire-*.so $(php -r "echo ini_get ('extension_dir');")/blackfire.so \
    && printf "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8707\n" > $PHP_INI_DIR/conf.d/blackfire.ini \
    && rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz

我将该行改为 const filters = () => { const [anchorEl, setAnchorEl] = useState(null) const popoverOpen = Boolean(anchorEl) const handleTogglePopover = (event: any) => { event.preventDefault() if (anchorEl === null) { setAnchorEl(event.currentTarget) } else { setAnchorEl(null) } } const SortActions = () => { return ( <Box> <MyCustomRadioButton/> </Box> ) } const FilterButtons = () => { return ( <Box> <ButtonBase onClick={handleTogglePopover} aria-owns={popoverOpen ? 'my-popover-id-name' : undefined} aria-haspopup={true} > {/* contents (this is a comment in html in react) */} </ButtonBase> <Popover id={'my-popover-id-name'} open={popoverOpen} anchorEl={anchorEl} anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }} transformOrigin={{ vertical: 'top', horizontal: 'left' }} onClose={handleTogglePopover} > <SortActions/> </Popover> </Box> ) } return ( <Box> {/* THIS LINE IS THE LINE I CHANGED TO GET IT TO WORK */} <FilterButtons/> </Box> ) } 。看起来呈现弹出窗口的组件需要存在于调用它的功能组件中。 但是,其下的任何嵌套组件都不需要在调用功能组件中声明。

从我收集的许多人的解决方案来看,为此使用 React.memo 但这对我有用。当它作为嵌套组件而不是组件内的函数调用时,React 重新渲染会丢失状态的弹出窗口会导致状态丢失吗?我认为这与 JavaScript 在函数内封装的工作方式有关。

我知道这是一个较老的问题,但我知道人们最终仍会回答这个问题。