错误 Cannot read 属性 'left' of undefined in React Semantic UI Popup with Styled Component

Error Cannot read property 'left' of undefined in React Semantic UI Popup with Styled Component

我有一个这样的样式组件:

import styled from 'styled-components';
const TagIcon = styled(Icon).attrs({
  name: 'tag',
})`
  cursor: pointer;
  font-size: 14px !important;
`

如果我在语义-ui-react 布局中使用它,它在大多数情况下都可以正常工作。但是,如果我将它用作 SUI Popup 组件的触发器,则会导致崩溃:

<Popup content="Test Popup" trigger={<TagIcon />} />
Load Page = ... Unhandled Rejection (TypeError): Cannot read property 'left' of undefined
getBoundingClientRect
src/utils/getBoundingClientRect.js:38
  35 | catch(e){}
  36 | 
  37 | const result = {
> 38 |   left: rect.left,
     | ^  39 |   top: rect.top,
  40 |   width: rect.right - rect.left,
  41 |   height: rect.bottom - rect.top,
...
Popper.update$
src/index.js:94
  91 | // We can't use class properties because they don't get listed in the
  92 | // class prototype and break stuff like Sinon stubs
  93 | update() {
> 94 |   return update.call(this);
     | ^  95 | }
  96 | destroy() {
  97 |   return destroy.call(this);

如果我用 equivalent(ish) 组件替换 "TagIcon" 样式组件,它工作正常:

<Popup content="Test Popup" trigger={<Icon name="tag">} />

有人遇到过这个问题并有解决方案吗?如果这是一个问题,我不确定应该在哪个 git 项目中报告,因为看起来样式化组件和语义组件之间的幕后工作方式可能存在冲突-ui-反应(或者也可能是语义-ui)。

我遇到了同样的问题,调试了几个小时,终于发现其实很容易解决!问题是由于某种原因 popper.js 没有收到 DOM ref 来计算 left/top/width/height,所以你需要使用 forwardRef 和 ref 将它传递下来 "manually",例如:

// Your Icon component 
const Icon = forwardRef(
  (props, ref) => (
    <img
      src={props.url}
      ref={ref}
    />
  )
);

之后就可以正常使用了:

const TagIcon = styled(Icon)`
  width: 40px;
`

<Popup content="Test Popup" trigger={<TagIcon url="https://test-image.com">} />

希望对大家有所帮助!

更新:选项 1

另一种解决方案可能是这里最简单的解决方案,它是用一个普通的 HTML 标记包装您的触发元素,并向其添加一个引用以用作 Popup 的上下文,例如所以:

import React, { createRef } from 'react';
import { Button, Popup } from 'semantic-ui-react';

const StyledButton = styled(Button)`
  color: purple;
`

class PopupUser extends React.Component {
  contextRef = createRef()

  render() {
    return <Popup
          trigger={<span ref={this.contextRef}>
            <StyledButton content='Trigger Popup' />
            </span>}
          context={this.contextRef}
          content='Hello'
          position='top center'
        />;
  }
}

注意: 这可能并不总是一个选项,具体取决于您使用的 trigger,但应该适用于大多数用例 - 请务必交换一个span 对于 div 如果换行 block elements.


选项 2

与帕特里克的回答类似,您需要包装触发器组件才能使其在语义 UI 弹出窗口中正常运行。

如果您打算使用 Semantic UI Icon component,您可以像这样包装它:

const Icon = forwardRef(
    ({className, name, ...props}, ref) =>
        <i
            aria-hidden="true"
            className={`${name} icon ${className}`}
            {...props}
            ref={ref}
        />

);

再说一遍,然后正常使用它:

const TagIcon = styled(Icon)`
  width: 40px;
`

} />

注意:我尝试直接包装Icon组件,而不是重新创建一个小版本的组件,但效果并不好