Component Composition
We will show you how to use composition to improve your code. Composition enables you to build complex UIs out of simple components.
What is Component Composition?
Component composition is the idea of using a component inside another component. This compelling idea allows you to build complex UIs out of simple components.
We did this in the last section when we refactored the label, the input, and the button into a single component called AddTask
, which we then used inside the Page
component.
But let's look at a more specific case of composition.
TaskList and TaskListItem
We currently have a list of tasks we're rendering in the Page
component. Let's extract that into a separate component called TaskList
.
Now, we can use this component inside the Page
component.
Let's also extract the TaskListItem
component from TaskList
.
Now, we can use this component inside the TaskList
component.
Our code is now more modular and easier to understand. Our UI is now composed of smaller components, too.
This refactoring sounds okay, but we are passing a lot of unnecessary props compared to our initial implementation and lose some natural semantics in our code.
- We pass the
title
prop to theTaskListItem
component. It would be nicer if we could pass it like<TaskListItem>{task.title}</TaskListItem>
. - We pass the
tasks
prop to theTaskList
component and just forward the title from it to theTaskListItem
component. How can we fix this?
Let's remove these unnecessary props by using composition.
Refactoring TaskListItem
Instead of passing the title
prop to the TaskListItem
component. Let's have a more natural API for it. We'll pass the title as slot content to the TaskListItem
component.
Now, we can use the TaskListItem
component like this.
Refactoring TaskList
Now, let's refactor the TaskList
component. Instead of passing the tasks
prop to the TaskList
component, let's pass slot content to the TaskList
component.
Now, we can use the TaskList
component like this. Remember to import the TaskListItem
component.
This code feels more natural and we're not passing any unnecessary props.
Technically speaking, we are still passing the same props but in a different way.
Let's see how powerful our composition is now. Assume we must show the number of tasks in the TaskList
component. We can easily do that by adding a new component called TaskListHeader
and using it inside the TaskList
component.
Now, we can use this component inside the Page
component.
But we have a problem. The TaskListHeader
component is not a list item inside the TaskList
component. We can solve this issue by creating a named slot
called header
in the TaskList
component and passing the TaskListHeader
component to that named slot
.
Passing the TaskListHeader
with a slot="header"
will render the TaskListHeader
component at the specified location.
Note how we pass the TaskListHeader
component as a header
slot to the TaskList
component. This is how real composition works and is very powerful.
Performance Benefits
There are also performance benefits to using composition. Let's say our TaskList
component has a simple timer that updates every second. This would require state and effect in the TaskList
component, but would that re-render the TaskListItem
or the TaskListHeader
component? Let's find out.
Let's add a console.log
in the TaskListItem
component with afterUpdate
.
What do you see in the console? You should see that the TaskListItem
component is not re-rendered. This is the power of composition.
This is a very powerful feature of most UI frameworks and can take time to wrap your head around. But once you do, you can write performant and readable code without fancy optimizations. We recommend reading the article below for a more detailed explanation.
- Svelte Design Patterns by Eric Liu
Great, you can remove the console.log
and the afterUpdate
statements.
In the next section, we'll summarise and leave you with a few suggestions for continuing this project to end up with a resume-worthy project.
At this point, your code should be a good match to the branch of the repository: 8-component-composition