2

I want to create a reusable component where the DOM structure can be different each time the component is rendered. Let's say I have this

class Comp extends React.Component {
    constructor() {
        super()
        this.state = {
            click: null,
        }
    }
    render() {
        return(
            <div>
                {this.props.chidren}
            </div>
        )
    }
    handleButton1() {
        this.setState({click: 'button1'});
    }
    handleButton2() {
        this.setState({click: 'button2'});
    }
}
class SubComp1 extends React.Component {
    render() {
        return(
            <button onClick={() => this.props.handleButton1()}>Button 1</button>
        )
    }
}
class SubComp2 extends React.Component {
    render() {
        return (
            <button onClick={() => this.props.handleButton2()}>Button 2</button>
        )
    }
}
ReactDOM.render((
<Comp>
    <div id="somediv">
        <div id="andanother">
            <SubComp1 />
        </div>
    </div>
    <div id="andanotherother">
        <SubComp2 />
    </div>
</Comp>), document.getElementById('app'))

Currently, the two subcomponents do not have access to their respective handler functions. What's the best way of passing the functions handleButton1 and handleButton2 to the subcomponents assuming that their position in the DOM is dynamic and might change depending on the layout of the page. I have thought of 2 solutions so far:

  1. Iterating inside the props.children until I find the element of interest then clone it with the property

  2. Using ref and somehow render the subcomponents after the main component has been rendered through the componentDidMount callback.

What are your thoughts on this?

1
  • 1
    Could you highlight your problem? Commented Jul 12, 2017 at 20:50

3 Answers 3

2

This is a place where using React's Context would be the most straightforward solution.

Another solution would be to use Redux actions, but that would make your component less reusable and more tightly coupled with your application, which you may or may not care about.

Sign up to request clarification or add additional context in comments.

4 Comments

(The first example in the linked React Context documentation should tell you enough about how to go about implementing it)
Thanks! This looks like a working solution. I'll try it and get back to you.
It worked perfectly! I also figured out another solution involving passing the instance of the components to the subcomponents but it required some trick. This worked exactly as expected, thanks!
@BinyuanSun Glad to know that
2

Why not do something like this:

class Comp extends React.Component {
    constructor() {
        super()
        this.state = {
            click: null,
        }
    }
    render() {
        return(
            <div>
                {this.props.chidren}
            </div>
        )
    }
    handleButton(button) {
        this.setState({click: button});
    }
}

Then in the subcomponents you can do something like

class SubComp1 extends React.Component {
    render() {
        return(
            <button onClick={() => this.props.handleButton('button1')}>Button 1</button>
        )
    }
}

class SubComp2 extends React.Component {
    render() {
        return (
            <button onClick={() => this.props.handleButton('button2')}>Button 2</button>
        )
    }
}

3 Comments

By doing that, does the subcomponents have access to the this.props.handleButton from the parent?
I misunderstood your question, in that case using React.cloneElement with the appropriate props seems like a good option.
But the problem would be that it might have to loop through it a lot before finding the desirable element, depending on the level of nesting.
1

One Alternative option which might fit your needs is to build a higher order component, which decorates another component with some additional functionality, below is a quick example of how this may work for you,

The higher order component:

const Comp = ComposedComponent =>
  class Comp extends React.Component {
    constructor(props) {
        super(props)
        this.handleButton = this.handleButton.bind(this);
        this.state = {
            click: null,
        }
    }

    handleButton(button) {
      this.setState({click: button}); 
    }

    render() {
        return(
            <ComposedComponent
              onClick={this.handleButton}
            />
        )
    }
  }

  export default Comp;

The child component:

class SubComp1 extends React.Component {
    render() {
        return(
            <button onClick={() => this.props.onClick('button1')}>Button 1</button>
        )
    }
}

How to use it:

const ExtendedComp = Comp(SubComp1);

<ExtendedComp />

would this be suitable for your task?

2 Comments

If I was to do const ExtendedComp1 = Comp(SubComp1); and const ExtendedComp2 = Comp(SubComp2);, would they be modifying the same state.click?
No because they are separate instances, the higher order component simply takes a component as a parameter and extends its functionality. Generally the state in react should be related to the ui, and if you intend on having many different components accessing a global state throughout your application maybe you should consider using a state management library such as redux or mobX

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.