Sam Walpole
Sam Walpole

Reputation: 1184

Pass props to all instances of same component

In my React app I am conditionally rendering views depending on which button is clicked in my menu component by passing the a changeView method as props from the parent to the menu. The current view is stored as state in the parent component.

I also want to use this same changeView method to control a button in each conditionally rendered view to go back to the menu on click.

I am currently achieving this as so:

render() {
  let view;
  switch(this.state.view) {
    case 0:
      view = (<Menu changeView={this.changeView} />);
      break;
    case 1:
      view = (<View changeView={this.changeView}>Test 1</View>);
      break;
    case 2:
      view = (<View changeView={this.changeView}>Test 2</View>);
      break;
    default:
      view = (<View changeView={this.changeView}>An error has ocurred!</View>);
  }

  return (
    <div>
      {view}
    </div>
  );
}

As you can see I am having to pass the changeView method individually to each instance of the View component. Is there any way to set up the View component so that every instance is passed the changeView prop without me having to explicitly declare it each time?

Upvotes: 1

Views: 242

Answers (4)

Ori Drori
Ori Drori

Reputation: 191976

All you need is the changing text inside the view. Move the text to an array outside of the component, and select the text by the view index or fallback to the error:

const text = ['', 'Test 1', 'Test 2'];

class Demo extends React.Component {
  state = {
    view: 1
  }

  render() {  
    const { view } = this.state;
    const text = text[view] || 'An error has ocurred!';

    return (
      <div>
        {view === 0 ?
          <Menu changeView={this.changeView} />
          :
          <View changeView={this.changeView}>{text}</View>
        }             
      </div>
    );
  }
}

Upvotes: 0

Anurag Awasthi
Anurag Awasthi

Reputation: 6233

You can create a function to do that for you,

getView(Component, children){
    return <Component changeView = {this.changeView}>{children}</Component>
}

render() {
  let view;
  switch(this.state.view) {
    case 0:
      view = getView(Menu)
      break;
    case 1:
      view = getView(View,'Test 1')
      break;
    case 2:
      view = getView(View,'Test 2')
      break;
    default:
      view = getView(View,'An error has ocurred!');
  }

  return (
    <div>
      {view}
    </div>
  );
}

Upvotes: 0

dotconnor
dotconnor

Reputation: 1786

Try moving the switch statement inside the View component

render() {
  return (
    <div>
      {this.state.view === 0 && <Menu changeView={this.changeView} />}
      {this.state.view > 0 && <View changeView={this.changeView}>
      {() => {
        switch (this.state.view) {
          case 1:
            return 'Test 1';
          case 2:
            return 'Test 2';
          default:
            return 'An error has ocurred!';
        }
      }}
      </View>
    </div>
  );
}

Upvotes: 3

Tholle
Tholle

Reputation: 112787

You could change your switch to just change copy and component if needed instead.

render() {
  let copy = "";
  let Component = View;

  switch (this.state.view) {
    case 0:
      Component = Menu;
      break;
    case 1:
      copy = "Test 1";
      break;
    case 2:
      copy = "Test 2";
      break;
    default:
      copy = "An error has ocurred!";
  }

  return (
    <div>
      <Component changeView={this.changeView}>{copy}</Component>
    </div>
  );
}

Upvotes: 1

Related Questions