0
import React from 'react';
import {FirstCustomComponent} from './somewhere';
import {SecondCustomComponent} from './somewhere-else';

const ThirdCustomComponent = ({componentTitle, apple, banana}) => (
 componentTitle === 'FirstCustomComponent' 
    ? <FirstCustomComponent apple={apple} banana={banana} />
    : <SecondCustomComponent apple={apple} banana={banana} />

);

export default ThirdCustomComponent;

What is a good way to avoid the repetition in the code sample above? I've tried dynamically generating a component by setting const DynamicComponent = props.componentTitle and then returning <DynamicComponent apple={props.apple} banana={props.banana} /> but no luck.

TDB
  • 367
  • 1
  • 3
  • 15
  • You're close; the problem is that `props.componentTitle` is still a string but JSX is expects an actual Component. Something like `const DynamicComponent = componentTitle === 'FirstCustomComponent' ? FirstCustomComponent : SecondCustomComponent;` should work – Hamms Mar 17 '18 at 00:15
  • Interested in your thoughts on my solution. Let me know if that works for you. – Dan Zuzevich Mar 17 '18 at 01:47
  • Interesting approaches in all the answers and belated thanks to all, but @Hamms comment got me where I was looking to go. Hamms if you convert your comment into an answer I'll mark it as such. – TDB Mar 26 '18 at 11:38

6 Answers6

1

they're multiple ways to do this, if you don't want to import all elements into your pages, you could have a "middle" file create an object with all your elements, you could do something like this:

first.js

class First extends Component {
  render(){
    return (
    <div>
      <span>first</span><br/>
      <span>{this.props.title}</span>
    </div>
  )
  }
}

second.js

class Second extends Component {
  render(){
    return (
      <div>
        <span>second</span><br/>
        <span>{this.props.title}</span>
      </div>
    )
  }
}

objects.js

import First from './first.js'
import Second from './second.js'
const objects = {
  "First": First,
  "Second": Second,
}

import objects from './objects'

class Third extends Component {
  render(){
    const Type = objects[this.props.type];
    return (
      <div>
        <Type title={this.props.title}/>
      </div>
    )
  }
}

Main.js

class App extends Component {
  render() {
    return (
      <div className="App">
        <Third title={'hello'} type={'First'} />
      </div>
    );
  }
}
josesuero
  • 3,260
  • 2
  • 13
  • 19
0

You can pass a Component as a prop. The component must be a valid react component; i.e. either a function that returns JSX or an implementation of React.Component

const ThirdCustomComponent = ({component: Component, apple, banana}) => (
    <Component apple={apple} banana={banana} />
);

// Using ThirdCustomComponent
import FirstCustomComponent from './FirstCustomComponent';

const apple = {...};
const banana = {...};    

const Container = () => (
  <ThirdCustomComponent 
     component={FirstCustomComponent} 
     apple={apple} 
     banana={banana} 
  />
);
SrThompson
  • 5,568
  • 2
  • 17
  • 25
0

You might like this approach if you are utilizing ES6 arrow functions in your React application. It utilizes the concept of an immediately invoked function. Its just generic JavaScript. Isn't that why we all write React in the first place? Well, and because we are smarter than the people that use Angular and Vue... =)

class Dynamic extends React.Component {
  render() {
    return (
      <div>
        {
          (() => {
            switch(this.props.title) {
              case 'one':
                return <One />
              case 'two':
                return <Two />
              default:
                return null            
            }
          })()
        }
      </div>
    )
  }
}

const One = () => <div className="one"> Component One </div>
const Two = () => <div className="two"> Component Two </div>

ReactDOM.render(
  <Dynamic title="one" />,
  document.querySelector('#app')
)

I have included a working example on Codepen as well.

Dan Zuzevich
  • 3,651
  • 3
  • 26
  • 39
0
const ThirdCustomComponent = ({componentTitle, apple, banana}) => {
  const DynamicComponent =
    componentTitle === 'FirstCustomComponent'
    ? FirstCustomComponent
    : SecondCustomComponent;

  return React.cloneElement(DynamicComponent, {
    { apple, banana }
  }
};

Please try above code snippet.

Basically, React.cloneElement(Component, props) is the Solution.

0

You're close; the problem is that props.componentTitle is still a string but JSX is expects an actual Component. Specifically, (as explained in this SO answer), <DynamicComponent /> compiles to React.createElement(DynamicComponent , {}), so you can do something like this

const FirstCustomComponent = () => (
  <p>First</p>
)
const SecondCustomComponent = () => (
  <p>Second</p>
)

const ThirdCustomComponent = ({componentTitle}) => {
  const DynamicComponent = componentTitle === 'FirstCustomComponent' 
      ? FirstCustomComponent
      : SecondCustomComponent;
  return <DynamicComponent />;
}

ReactDOM.render(<div>
  <ThirdCustomComponent componentTitle="FirstCustomComponent" />
  <ThirdCustomComponent componentTitle="SecondCustomComponent" />
</div>, document.getElementById("container"));
<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="container" />
Hamms
  • 5,016
  • 21
  • 28
-1

Probably you can achieve this using code similar to below (suppose you want to pass component names instead of component references)

const First = ({a, b}) => <h1>1-{a}-{b}</h1>
const Second = ({a, b}) => <h1>2-{a}-{b}</h1>

const Comp = {
  First,
  Second,
} // we have Babel, ES6 object notation okay

const App = ({title, a, b}) => React.createElement(Comp[title], {a, b}) // just for one-liner, if you know React w/o JSX

/* Same as
const App = ({title, a, b}) => {
  const Tag = Comp[title]
  return <Tag a={a} b={b} />
}
*/

ReactDOM.render(<App a="apple" b="banana" title="First" />, 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>
Kevin Qian
  • 2,532
  • 1
  • 16
  • 26