Nate
Nate

Reputation: 6454

React: Nested Reusable Composition Components within a Higher Order Component

I've been trying to wrap my head around this problem for a while. I've hacked together a solution that works, until I get any nested divs, then things fall apart. Basically what I'm trying to do is create composition components that live within a higher order component and all share the same current state. I then need to export that so that any file can use those components. So here's what the JSX might look like:

<Panel countersStartAt=5>
  <Counter incrementsBy=1 />
  <div>
    <Counter incrementsBy=2 />
  </div>
  <TotalCounter className="someclass" />
</Panel>

So the way I want something like this to work is that I have this wrapper Panel component that sets some initial state, say this.state.start = 5. Within Panel, a Counter component would have an onClick handler that increments state.start by incrementsBy. And TotalCounter would be a component that displayed state.start. Of course this is a contrived example, so it would be helpful not to bring up how I could make this particular component better. I'm looking to apply this to a more realistic situation.

The second thing would be how to export those components in a way that I can create the exact code above in a separate file within a stateless component. Hopefully that makes sense.

This is a snippet of what I'm doing to achieve this.

  renderChildren = (children) => {
    return React.Children.map(children, (child) => {
      if (React.isValidElement(child)) {
        return React.createElement(
          (child.type.name ? this[child.type.name] : child.type),
          child.props
        );
      }
      return child;
    });
  };

  render = () => {
    return (
        {this.renderChildren(this.props.children)}
    )
  };

Then outside of the Panel class I'm exporting like so:

export const Counter = () => null;

Just so it exposes Counter. The default render of null doesn't happen because I replace Counter with the this.Counter() method within Panel.

Questions asked in Comments and Other things to consider

Upvotes: 2

Views: 1153

Answers (1)

John Ruddell
John Ruddell

Reputation: 25842

To put in an answer here for what we talked about in the chat room

the best way to handle what you want to do without a data management framework like Redux or Flux is to pass your data as props through, like so.

class Panel extends Component {

    constructor(){
      super()
      this.state = {count: 5}
    }
    incrementCount = (incrementer) => {
      this.setState({count: this.state.count + incrementer});
    }
    render (){
      return (
        <div>
          <Counter incrementCount={this.incrementCount} count={this.state.count} incrementsBy=2 />
        </div>
      );
    }

}

then in your counter..

<someElement onClick={ (e) => {this.props.incrementCount(this.props.incrementsBy)} }>{this.props.count}</someElement>

Upvotes: 1

Related Questions