简体   繁体   中英

Can't unmount React component, returning false from parent component

I'm trying to perform authorization on a child component against certain permissions. I'm using ref callback to get access to the Node, wherein I can check permissions. Depending on these permissions, I would like to unmount the component.

Within the callback, I'm trying to use ReactDOM.findDOMNode() and then ReactDOM.unmountComponentAtNode() to remove it. The latter keeps returning false, although findDomNode appears to properly be selecting the DOM element.

class Auth extends React.Component {

    ...

    checkPermissions(component) {
        const domNode = ReactDOM.findDOMNode(component); // => <p>...</p>

        if (domNode) {
            let wasUnmounted = ReactDOM.unmountComponentAtNode(domNode);
            console.log('was unmounted', wasUnmounted); // => false
        }
    }

    render(){
        return (
            <div>
                {this.state.authorized &&
                    <Component ref={(c) => this.checkPermissions(c)} {...this.props} />
                }
            </div>
        )
    }

    ...

How can I use ReactDOM.unmountComponentAtNode() to effectively remove my component?

I don't think you'll want to mount your node just to check permissions and then unmount it. You should check permissions before you render. Not only is it more secure, but it's also simpler.

If the user is authorized, you render the component. If the user is not authorized, you render something else.

So something kind of like this:

render() {
  if (!this.state.authorized) {
    return <PleaseLogIn />;
  }

  return (
    <div>
      <Component {...this.props} />
    </div>
  );
}

If you find yourself manipulating the DOM manually, take a step back and make sure there's not a more "Reacty" way to do it.

Update:

If you want a wrapper component that you can put around things that should or shouldn't render its children based on permissions maybe you do something like this:

// state.userPermissions = ['permission1', 'permission1', 'betaTolerant'];

const AuthWrapper = React.createClass({
  propTypes: {
    userPermissions: React.PropTypes.array.isRequired,
    requiredPermissions: React.PropTypes.array.isRequired,
    children: React.PropTypes.node.isRequired
  },

  isAllowed() {
    const { userPermissions, requiredPermissions } = this.props;
    return requiredPermissions.some((requiredPermission) => {
      return userPermissions.some((userPermission) => {
        // If this ever returns true, isAllowed will return true
        // Meaning: If any of the requiredPermissions match
        // any of the userPermissions
        return requiredPermission === userPermission;
      });
    });
  },

  render {
    if(!this.isAllowed()) return null;
    return this.props.children;
  };
});

const mapStateToProps = (state) => {
  // Only this auth component has access to state
  return {
    userPermissions: state.userPermissions
  };
};

export default connect(
  mapStateToProps,
  null
)(AuthWrapper);

Now you can use this wrapper like:

// Inside some component
render {
  return (
    <MyApp>
      <NormalFeature />
      <AuthWrapper requiredPermissions=['secretFeature', 'betaTolerant']>
        <SecretFeature />
      </AuthWrapper>
    </MyApp>
  );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM