AJ Meyghani
AJ Meyghani

Reputation: 4589

Reduce duplicated boilerplate code in React

I'm quite new to React and I don't know if there is a pattern to reduce duplicated code. I'm aware of higher order components but I'm not sure how/if they can help me. Here is the issue that I'm having:

Here is the scenario:

I have three React components in my app: Studios, Projects, Actors

Each component corresponds to a route on the front-end:

Each component does pretty much the same thing, looping through the items and render a component:

Now the model for a Project, Studio, and Actor are pretty much the same with slight variation:

Also, on the "List" view, when I click on an item, it takes me to the details of that item. For example, when I am on the /projects view when I click on a project item, it takes me to /projects/:id and renders the ProjectDetail component. So by now for each entity I have three components: ItemList, Item, ItemDetail. Which is total of 3 x 3 = 9 components. I feel like there is a better way of doing this. Maybe I don't understand the responsibility of the router? Right now, I have a route for the ItemList and ItemDetail for every entity:



Eventually I would like to generalize models that are very similar to each other to reduce boilerplate code. Possibly:

and a generic client route rule that can automatically map the route to the appropriate component.

Upvotes: 3

Views: 591

Answers (1)

Ryan Kennedy
Ryan Kennedy

Reputation: 3615

I'm going to refer to components vs instances in my answer; check out this article for an explanation of the differences, or read this TL;DR: a component is the class or function that specifies the behavior of a JSX tag, while an instance is typically represented by JSX in a render method. So function Foo() { return <div />;} would be a component, while <Foo /> would be an instance.

The magic of JSX is that tag names are simply variables. For instance, when you type <div />, the tag name is simply referring to a div variable defined by React core. Assuming you've imported a component Foo, when you type <Foo /> then the tag name is referring to the variable you've brought in scope by importing.

You could use a higher-order component that takes a React component, and then use that component in the render method. For example (disclaimer, I'm writing this on-the-fly and it may contain errors):

// Assume the variables `studios, actors, projects` are arrays
// of their respective item types, and `StudioDetail, ActorDetail,
// ProjectDetail` are the customized views you've described in
// your question.

class ItemList extends React.Component {
  render() {
    const View = this.props.view;
    const items = this.props.items;
    return (<div>
      {items.map((item, i) => <View key={i} item={item} />}
    </div>);
  }
}

class App extends React.Component {
  render() {
    return (<div>
      <ItemList view={StudioDetail} items={studios} />
      <ItemList view={ActorDetail} items={actors} />
      <ItemList view={ProjectDetail} items={projects} />
    </div>);
  }
}

Just make sure that whatever you pass into the view prop is a component matching the type of item you're showing, and you ought to be off to a good start.

Upvotes: 3

Related Questions