Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

  • /projects: Projects
  • /studios: Studios
  • /actors: Actors

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

  • Projects: loop through the data for projects and render a Project component for each project

  • Studios: loop through the data for studios and render a Studio component for each studio

  • Actors: loop through the data for actors and render an Actor component for each actor

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

  • Studio: image, name, details
  • Actor: image, name, and bio
  • Project:image, title, and description

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:

  • /projects: Projects
  • /projects/:id: ProjectDetail

  • /actors: Actors
  • /actors/id: ActorDetail

  • /studios: Studios
  • /studios/:id: StudioDetail

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

  • ItemList: would take data as an input and render the appropriate Item component.
  • Item: The component that would show up on the ItemList
  • ItemDetail: The component that shows the details of the Item

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

like image 366
AJ Meyghani Avatar asked Dec 04 '25 16:12

AJ Meyghani


1 Answers

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.

like image 99
Ryan Kennedy Avatar answered Dec 06 '25 06:12

Ryan Kennedy