Reputation: 4589
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
Studios
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, detailsActor
: image, name, and bioProject
:image, title, and descriptionAlso, 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
ProjectDetail
Actors
ActorDetail
Studios
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.
Upvotes: 3
Views: 591
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