Components are the basic building blocks used in modern frontend frameworks like React, Vue, and Svelte. Well-written components can improve the overall structure of your app and make it clean and maintainable.
It's likely that you've heard about the presentational and container components pattern. In some cases, this might be a helpful pattern to use — but not always. I've used this pattern throughout a complex project and I've ended up with a lot of boiler-platy components.
After writing lots of components and building complex frontend applications, I realized that we have only two types of components: UI general-purpose components and app-specific components.
Understanding what they are for and how to write them will help you design better components and ultimately better application architecture.
UI general-purpose components
They are pure UI components that are not made for a specific application. They are used for general UI elements like multi-select inputs, modal boxes, pagination links, etc.
So these components:
- Can be shared easily from project to project
- Don’t depend on the state of the app
- Don't have access to global data
- Don't make AJAX requests
- Just take props and emit events
- Are good for npm packages
So UI libraries like Vuetify and Material-UI are considered UI general-purpose components.
App-specific components
They are components that you implement specifically for your app, and it doesn't make sense to use them somewhere else.
These components:
- Can be used only inside your app
- Depend on the state of your app
- Can have access to global data and use state management libraries like Vuex and Redux
- Can make AJAX requests directly
- Can use specific terminologies based on the app's domain — so name variables/functions whatever you want
- Can be reused throughout your app, but they don't have to
- Can take props and emit events
A good example is a form component. This component will only work inside your app. It can render its fields based on the state of your app, submit its data directly with an AJAX request, and be reused when updating the data instead of creating it.
So the key to writing better components is to not confuse the two component types. For example, you don't have to create a single component called Form and reuse it for all forms in your app. Instead create as many form components (with specific fields) as you need.
I hope you enjoyed this article. For more stuff like this, follow me on twitter @tahazsh and subscribe to my blog's rss feed.
Top comments (2)
Would you say this should be used in conjunction with presentational-container format, or instead of?
I would avoid using the presentational-container pattern as the main way to design my components.
But I would use it in those cases when I have some UI component that can be rendered using a different set of data based on the current page or the current state of the app.
Let's say, for example, you have a UI component (presentational component) that displays a chart that describes how posts are doing in your blog. This chart component can take a single post or a set of posts. Let's say that in some places you would use this chart to display how your latest post is doing, but in other places, you want to show how your team's latest posts are doing.
Assuming that you want to display each type of chart in multiple places, you would end up duplicating the logic of fetching your latest post and your team's latest posts each time you need to display that chart. What you can do instead is creating a container component for both chart types, and in each one, you would include the needed logic to fetch and format the posts before displaying them in the chart.
So if you want to display your-latest-posts chart in the sidebar and in the main section of the page, you would just do something like this:
As you can see, you don't have to rewrite how to fetch those posts, because it's already done in the container component. (btw, you don't have to add the suffix
Container
to it — name it whatever you want.)So in conclusion, this pattern is like any other pattern, use it when you need it. And don't try to follow the rules of that pattern strictly. So it's fine if you need to pass props to the container component.
I hope this clarifies things for you. Please don't hesitate to ask further questions :).