Do you prefer JavaScript or TypeScript?
Are you coming from any of the following frameworks?

Understanding Components

What are Components?

Components are the building blocks of most frontend applications. They are the relatively small pieces of code which can be reused and combined to create larger and more complex applications.

In JSX based frameworks such as Solid.js, Preact, React and the likes, components are defined using a function which returns a JSX element. Here's an example of a simple component:

jsx
function MyComponent() {
return <div>Hello World</div>
}
jsx
function MyComponent() {
return <div>Hello World</div>
}

This component can then be used in other components or in the main application component. For example, we can use the component we just created in the main application component like this:

jsx
function App() {
return (
<div>
<MyComponent />
</div>
)
}
jsx
function App() {
return (
<div>
<MyComponent />
</div>
)
}

What is a Component Tree?

A component tree is a tree structure which represents the components in your application. The root of the tree is the main application component. Each component in the tree can have zero or more children. The children of a component are the components which are rendered inside of it.

For example, the component tree for the application we just defined will look like this:

App
└── MyComponent
App
└── MyComponent

Component trees can get very complex and large. For example, the component tree for a large application might look like this:

App
├── Header
├── Sidebar
├── Content
│ ├── Post
│ │ ├── PostHeader
│ │ ├── PostContent
│ │ └── PostFooter
│ ├── Post
│ │ ├── PostHeader
│ │ ├── PostContent
│ │ └── PostFooter
| └── Post
│ ├── ...
└── Footer
App
├── Header
├── Sidebar
├── Content
│ ├── Post
│ │ ├── PostHeader
│ │ ├── PostContent
│ │ └── PostFooter
│ ├── Post
│ │ ├── PostHeader
│ │ ├── PostContent
│ │ └── PostFooter
| └── Post
│ ├── ...
└── Footer

From the above illustration we can see that components can have children which are also components. This is what makes components so powerful. They allow us to break down our applications into smaller and more manageable pieces.

Why are Components Different in Solid?

In Solid, components are defined using a function which returns a JSX element. However, the functions lifecycle ends once it has been run for the first time. This means that the function will not be re-run when the application state changes. This is different from other frameworks such as React, where functions are defined and run every time the application state changes.

This mechanism that Solid makes use of can be called setup functions as opposed to other frameworks render functions. This is because the function is only run once, and is used to setup everything that needs to be tracked by the reactive system. This is a very important distinction to make when learning Solid.

Here's an example of what all this means:

jsx
function MyComponent() {
const [count, setCount] = createSignal(0)
// This will only be run once and will not be re-run when the application state changes
console.log(count())
return (
<div>
<p>Count: {count()}</p>
<button onClick={() => setCount(count() + 1)}>Increment</button>
</div>
)
}
jsx
function MyComponent() {
const [count, setCount] = createSignal(0)
// This will only be run once and will not be re-run when the application state changes
console.log(count())
return (
<div>
<p>Count: {count()}</p>
<button onClick={() => setCount(count() + 1)}>Increment</button>
</div>
)
}

As you can see in the above code there's a console.log(count()) statement. This will only be run once, and will not be re-run when the application state changes. This is because the function is only run once, and is used to setup everything that needs to be tracked by the reactive system.

In order to make the console.log(count()) statement run every time the count state changes, we need to use a createEffect primitive. This primitive will run the function every time the count state changes. Here's an example of how this can be done:

jsx
function MyComponent() {
const [count, setCount] = createSignal(0)
// This will be run every time the count state changes
createEffect(() => {
console.log(count())
})
return (
<div>
<p>Count: {count()}</p>
<button onClick={() => setCount(count() + 1)}>Increment</button>
</div>
)
}
jsx
function MyComponent() {
const [count, setCount] = createSignal(0)
// This will be run every time the count state changes
createEffect(() => {
console.log(count())
})
return (
<div>
<p>Count: {count()}</p>
<button onClick={() => setCount(count() + 1)}>Increment</button>
</div>
)
}

It's little differences like these that tend to throw people off when they first start using Solid. However, once you get used to it, it's actually a very powerful and flexible mechanism.

Here is another example of how Solid components are different from React components:

jsx
function MyComponent() {
const [count, setCount] = createSignal(0)
if(count() > 5) {
return <div>Count limit reached</div>
}
return (
<div>
<p>Count: {count()}</p>
<button onClick={() => setCount(count() + 1)}>Increment</button>
</div>
)
}
jsx
function MyComponent() {
const [count, setCount] = createSignal(0)
if(count() > 5) {
return <div>Count limit reached</div>
}
return (
<div>
<p>Count: {count()}</p>
<button onClick={() => setCount(count() + 1)}>Increment</button>
</div>
)
}

In the above example, the component will not return the Count limit reached div if the count is greater than 5. This is because the component itself is not reactive and is only used once so it does not know when the state of count gets above 5. In order to make the Count limit reached visible, we need to use add it to a reactive scope like the returned JSX and make use of the logic in there. Here's an example of how this can be done:

jsx
function MyComponent() {
const [count, setCount] = createSignal(0)
return (
<div>
{count() > 5 ? <div>Count limit reached</div> :
<>
<p>Count: {count()}</p>
<button onClick={() => setCount(count() + 1)}>Increment</button>
</>
}
</div>
)
}
jsx
function MyComponent() {
const [count, setCount] = createSignal(0)
return (
<div>
{count() > 5 ? <div>Count limit reached</div> :
<>
<p>Count: {count()}</p>
<button onClick={() => setCount(count() + 1)}>Increment</button>
</>
}
</div>
)
}

The above code will work as expected and will show the Count limit reached div when the count is greater than 5. But this is what your code should look like when you're writing React not Solid. In Solid, you should make use of the built in control-flow components to achieve the same result except with better reactivity and optimization. Here's an example of how this can be done:

jsx
function MyComponent() {
const [count, setCount] = createSignal(0)
return (
<div>
<Show when={count() > 5} fallback={
<>
<p>Count: {count()}</p>
<button onClick={() => setCount(count() + 1)}>Increment</button>
</>
}>
<div>Count limit reached</div>
</Show>
</div>
)
}
jsx
function MyComponent() {
const [count, setCount] = createSignal(0)
return (
<div>
<Show when={count() > 5} fallback={
<>
<p>Count: {count()}</p>
<button onClick={() => setCount(count() + 1)}>Increment</button>
</>
}>
<div>Count limit reached</div>
</Show>
</div>
)
}

What are Component Props?

Component props are the properties which are passed to a component. They are used to pass data to a component. For example, we can pass a name prop to the MyComponent component we defined earlier like this:

jsx
function App() {
return (
<div>
<MyComponent name="John Doe" />
</div>
)
}
jsx
function App() {
return (
<div>
<MyComponent name="John Doe" />
</div>
)
}

The MyComponent component can then access the name prop like this:

jsx
function MyComponent(props) {
return <div>Hello {props.name}</div>
}
jsx
function MyComponent(props) {
return <div>Hello {props.name}</div>
}

Why Props destructuring is bad in Solid?

React developers might be used to destructuring props in the function arguments like this:

jsx
function MyComponent({ name }) {
return <div>Hello {name}</div>
}
jsx
function MyComponent({ name }) {
return <div>Hello {name}</div>
}

However, this is a very bad practice in Solid as you might be assuming that you are accessing the reactive value of the prop but that is not the case since the value itself will not be reactive but serve as a reference to the reactive value on the initial component setup. This means that if the prop value changes outside the component it will not be updated within the component.

In order to avoid this it is best to not destructure props in the function arguments and instead access them using the props object inside a reactive scope.

Here are some examples to further clarify this point:

  1. Accessing prop values outside of the reactive scope:
jsx
function MyComponent(props) {
// This is a bad practice and will not update within the component when the prop value changes
const name = props.name
// This is a good practice and will update within the component when the prop value changes
const [name, setName] = createSignal(props.name) // createSignal is a Solid.js primitive. More on this in the next page
return <div>Hello {name}</div>
}
jsx
function MyComponent(props) {
// This is a bad practice and will not update within the component when the prop value changes
const name = props.name
// This is a good practice and will update within the component when the prop value changes
const [name, setName] = createSignal(props.name) // createSignal is a Solid.js primitive. More on this in the next page
return <div>Hello {name}</div>
}
  1. Accessing prop values outside of the reactive scope using destructuring:
jsx
// This is a bad practice and will not update within the component when the prop value changes
function MyComponent(props) {
const { name } = props
return <div>Hello {name}</div>
}
// This is a good practice and will update within the component when the prop value changes
function MyComponent(props) {
return <div>Hello {props.name}</div>
}
jsx
// This is a bad practice and will not update within the component when the prop value changes
function MyComponent(props) {
const { name } = props
return <div>Hello {name}</div>
}
// This is a good practice and will update within the component when the prop value changes
function MyComponent(props) {
return <div>Hello {props.name}</div>
}
  1. Destructuring the props in the function arguments:
jsx
// This is a bad practice and will not update within the component when the prop value changes
function MyComponent({name}) {
return <div>Hello {name}</div>
}
// This is a good practice and will update within the component when the prop value changes
function MyComponent(props) {
return <div>Hello {props.name}</div>
}
jsx
// This is a bad practice and will not update within the component when the prop value changes
function MyComponent({name}) {
return <div>Hello {name}</div>
}
// This is a good practice and will update within the component when the prop value changes
function MyComponent(props) {
return <div>Hello {props.name}</div>
}