32

Within my component, how can I access the name of the parent component it is nested inside?

So if my render is thus:

ReactDOM.render(
      <RadialsDisplay data={imagedata}/>,
      document.getElementById('radials-1')
);

How can I retrieve the id name #radials-1 from within the component itself?

Union find
  • 7,759
  • 13
  • 60
  • 111

1 Answers1

52

It probably makes the most sense to pass it as a property, but if you really need to get it programmatically, and from inside the component, you can wait for the component to mount, find its DOM node, and then look at its parent.

Here's an example:

class Application extends React.Component {
  constructor() {
    super();
    this.state = { containerId: "" };
  }

  componentDidMount() {
    this.setState({
      containerId: ReactDOM.findDOMNode(this).parentNode.getAttribute("id")
    });
  }

  render() {
    return <div>My container's ID is: {this.state.containerId}</div>;
  }
}

ReactDOM.render(<Application />, document.getElementById("react-app-container"));

Working demo: https://jsbin.com/yayepa/1/edit?html,js,output


If you do this a lot, or want to be really fancy, you could utilize a higher-order component:

class ContainerIdDetector extends React.Component {
  constructor() {
    super();
    this.state = { containerId: "" };
  }

  componentDidMount() {
    this.setState({
      containerId: ReactDOM.findDOMNode(this).parentNode.getAttribute("id")
    });
  }

  render() {
    if (!this.state.containerId) {
      return <span />;
    } else {
      return React.cloneElement(
        React.Children.only(this.props.children),
        { [this.props.property]: this.state.containerId }
      );
    }
  }
}

ContainerIdDetector.propTypes = {
  property: React.PropTypes.string.isRequired
}

// Takes an optional property name `property` and returns a function. This
// returned function takes a component class and returns a new one
// that, when rendered, automatically receives the ID of its parent
// DOM node on the property identified by `property`.
function withContainerId(property = "containerId") {
  return (Component) => (props) =>
    <ContainerIdDetector property={property}>
      <Component {...props} />
    </ContainerIdDetector>
}

Here, withContainerId is a function that takes an argument called property and returns a new function. This function can take a component type as its only argument, and returns a higher-order component. When rendered, the new component will render the passed component, with all its original props, plus an additional prop specifying the parent container's ID on the property specified by the property argument.

You can use them with ES7 decorators (as currently implemented) if you wish, or via a regular function call:

@withContainerId()
class Application extends React.Component {
  render() {
    return <div>My containers ID is: {this.props.containerId}</div>;
  }
}

// or, if you don't use decorators:
//
// Application = withContainerId()(Application);

ReactDOM.render(<Application />, document.getElementById("react-app-container"));

Working demo: https://jsbin.com/zozumi/edit?html,js,output

Michelle Tilley
  • 157,729
  • 40
  • 374
  • 311
  • Is the state the best place for the parent ID since this isn't expected to change as component state gets updated through setState? – David Glass May 21 '16 at 10:49
  • 1
    @DavidGlass What is the alternative? If you set it on the instance itself (e.g. `this.containerId = ...`), then you have to add a `forceUpdate` call. `setState` automatically re-renders, and the container ID *is* part of the component's state, even if it doesn't change in the future. – Michelle Tilley May 22 '16 at 19:37
  • 1
    My bad, I didn't see where you were rendering the parent's ID to the node – David Glass May 24 '16 at 21:40
  • 1
    I'm not certain why, but your jsbin examples no longer seem to work. – Ryan Guill Mar 28 '17 at 16:03
  • Outdated references to ReactDOM have caused the jsbin to cease functioning. Great answer though! – Matt Williams Oct 05 '17 at 15:25