Lukáš Unzeitig Lukáš Unzeitig - 1 month ago 16
React JSX Question

Send to child which component child should render - React js

I have a

<div>
of multiple
<input>
, and an onClick event to open a modal window, which has to render certain div of inputs for closer zoom, but I am using this modal window for rendering a numpad too.

Is there any way to distinguish which component should be rendered? Is there a possibility to send certain component to modal component(child) and then render this component? I tried something like this -

<Modal update={this.editValue.bind(this)}>{Numpad}</Modal>


or

<Modal child={Numpad} update={this.editValue.bind(this)}/>


and then in Modal(child)

{React.cloneElement(this.props.children, { ...others})}


but it doesn't work, throwing invalid element type error. I can just use switch, inside render component of Modal to distinguish which component to render with props.type, but I want more simply way to do it, any tips?

Answer

As far as I understand you correctly, you try to create a tabbed interface within a modal window, so that you could show different content depending on currently active tab. I can see the following solution for that problem.

First, we create the basic component that will hold Modal component and its content:

class App extends React.Component {
  render() {
    return (
      <Modal>
        <div>The content of the first tab</div>
        <div>The content of the second tab</div>
        <div>The content of the third tab</div>
      </Modal>
    );
  }
}

Each child (div) component above represents the content for each tab in Modal.

Now let's create Modal component itself:

class Modal extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      tabIndex: 0
    };
  }

  switchTabs(tabIndex) {
    this.setState({
      tabIndex
    });
  }

  render() {
    return (
      <div>
        <button onClick={this.switchTabs.bind(this, 0)}>1</button>
        <button onClick={this.switchTabs.bind(this, 1)}>2</button>
        <button onClick={this.switchTabs.bind(this, 2)}>3</button>
        <div>
          {React.Children.map(this.props.children, (child, index) =>
            index === this.state.tabIndex && child
          )}
        </div>
      </div>
    )
  }
}

We keep the index of active tab (tabIndex) as a part of component's local state. We also show three buttons for switching between these tabs.

Finally, we iterate over components children using React.Children.map and show that child whose index corresponds to current tabIndex.

Try the snippet below.

class Modal extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      tabIndex: 0
    };
  }
  
  switchTabs(tabIndex) {
    this.setState({
      tabIndex
    });
  }

  render() {
    return (
      <div>
        <button onClick={this.switchTabs.bind(this, 0)}>1</button>
        <button onClick={this.switchTabs.bind(this, 1)}>2</button>
        <button onClick={this.switchTabs.bind(this, 2)}>3</button>
        <div>
          {React.Children.map(this.props.children, (child, index) =>
            index === this.state.tabIndex && child
          )}
        </div>
      </div>
    )
  }
}

class App extends React.Component {
  render() {
    return (
      <Modal>
        <div>
          <img src="https://avatars2.githubusercontent.com/u/4226954?v=3&s=400" height="200" />
        </div>
        <div style={{ height: '200px', width: '200px', marginTop: '5px' }}>The second tab</div>
        <div>
          <img src="https://avatars3.githubusercontent.com/u/810671?v=3&s=400" height="200" />
        </div>
      </Modal>
    );
  }
}

ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

Comments