反应高阶组件警告

时间:2019-06-21 08:39:47

标签: reactjs styled-components higher-order-components

我在响应中使用HOC来限制对组件的访问,但收到以下警告:validateDOMNesting(...):不能作为的后代出现。 HOC的完整代码(按要求)如下:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';

import * as selectors from '../../store/selectors';

class AccessRestrictedComponent extends Component {
  static propTypes = {
    auth: PropTypes.object.isRequired,
    mode: PropTypes.string.isRequired,

    useWithList: PropTypes.bool,
    checkItem: PropTypes.bool,

    restrictByRole: PropTypes.bool,
    restrictByMode: PropTypes.bool,
    allowedRoles: PropTypes.array,
    allowedModes: PropTypes.array,
    children: PropTypes.node.isRequired,
  };

  static defaultProps = {
    useWithList: false,
    checkItem: null,
    restrictByRole: false,
    restrictByMode: false,
    allowedRoles: [],
    allowedModes: [],
  };

  render() {
    const { auth, mode, restrictByRole, restrictByMode, allowedRoles, allowedModes, useWithList, checkItem } = this.props;
    const { role } = auth;

    if (useWithList && !checkItem) {
      return  (React.cloneElement(this.props.children, { ...this.props }));
    }

    if (restrictByRole && restrictByMode) {
      // console.log('restricting role and mode ');
      if (allowedRoles.includes(role) && allowedModes.includes(mode)) {
        // console.log(`role: ${role} and mode: ${mode} allowed.`);
        return (React.cloneElement(this.props.children, { ...this.props }));
      } return null;
    }
    if (restrictByRole) {
      // console.log('restricting role ');
      if (allowedRoles.includes(role)) {
        // console.log(`role: ${role} allowed.`);
        return (React.cloneElement(this.props.children, { ...this.props }));
      } return null;
    }
    if (restrictByMode) {
      // console.log('restricting mode ');
      if (allowedModes.includes(mode)) {
        // console.log(`${mode} allowed.`);
        return (React.cloneElement(this.props.children, { ...this.props }));
      } return null;
    }
    // console.log('component unrestricted');
    return (React.cloneElement(this.props.children, { ...this.props }));
  }
}

const mapStateToProps = state => ({
  state,
  auth: selectors.getAuth(state),
  mode: selectors.getMode(state),
});



export default  connect(mapStateToProps)(AccessRestrictedComponent);


我要包装的组件是样式化的组件NavButton。我这样使用HOC:

<AccessRestrictedComponent restrictByRole allowedRoles={[userRoles.ADMIN]}>
  <NavButton onClick={() => this.setState({ set: true })}>
    <Icon className="material-icons md-48" color={color}>{'wallpaper'}</Icon>
  </NavButton>
</AccessRestrictedComponent>

和样式化的组件是这样的:

export const NavButton = styled.button`
  display:flex;
  align-content:flex-end;
  align-self:flex-end;
  background: none;
  border: none;
  &:hover,
  &:focus{
    ${Icon}{
      cursor: pointer;
      color: ${props => props.theme.theme === themeTypes.LIGHT ? colors.SLATE_BLUE_50 : colors.lightBlue};
      border-radius: 4px;
      outline: none;
      background: linear-gradient(${colors.shuttleGrey}, ${colors.shuttleGrey}) padding-box,
                  repeating-linear-gradient(-45deg,
                    ${colors.submarine} 0, ${colors.submarine} 25%, transparent 0, transparent 50%
                  ) 0 / 8px 8px;
    }
  }
`;

我不明白此警告,因为我没有嵌套按钮,但是当我使用开发工具检查UI时,嵌套了两个按钮。有谁知道是什么原因造成的?它是样式化的组件吗? HOC,也许还有别的吗?我猜一个简单的解决方案是将样式化的组件更改为按钮以外的其他组件,但是我认为这应该是有效的代码。无论如何,任何建议都将不胜感激。

1 个答案:

答案 0 :(得分:1)

发生错误是因为克隆元素时,您将子对象传递给克隆的孩子作为道具。因此,您的父母克隆了button并将另一个按钮作为道具发送给克隆的按钮。

修正很简单,不要将children作为合并的道具发送。

render() {
  const { children, ...rest } = this.props;
  // ...rest
  return React.cloneElement(children, { ...rest });

  //...rest
}

这样,您就不会再次将children作为道具发送给children

注意:您应该替换所有React.cloneElement()通话