Thinking Solid
Solid's design incorporates a variety of viewpoints on principles and values that help us create better websites and applications. Knowing these underlying principles make it easier to learn and use Solid.
These particular principles will be covered in this section. To ensure that everyone understands these concepts, we will be talking about them at a high level.
1. Declarative Programming
Declarative programming refers to the practice of writing computer code that explains what your computer should do rather than how to accomplish it. It's like telling a chef to make an omelet - they know what to do.
Imperative programming tells the computer how to do something step by step. It's like telling someone how to make an omelet: "First, grab two eggs. Then, beat the eggs in a bowl with a fork. Melt some butter in a pan, then add the eggs." You are giving specific instructions on how to make the omelet.
Let's take a brief look at each of these approaches.
Declarative
js
let numbers = [1, 2, 3, 4, 5];let double = numbers.map((value, i) => value * 2);
js
let numbers = [1, 2, 3, 4, 5];let double = numbers.map((value, i) => value * 2);
In the code above, we have an array of numbers called numbers
. We then use the map
function to create a new array called double
that contains the values of numbers
multiplied by 2.
The map
function is a declarative function because it allows you to specify a transformation to be applied to each element of the array, without having to specify how that transformation is implemented.
Imperative
js
let numbers = [1, 2, 3, 4, 5];let double = [];for (let i = 0; i < numbers.length; i++) {double.push(numbers[i] * 2);}
js
let numbers = [1, 2, 3, 4, 5];let double = [];for (let i = 0; i < numbers.length; i++) {double.push(numbers[i] * 2);}
In the code above, we use a for loop to iterate through each element of the array, one at a time. Inside the loop, we use the push
method to add the result of doubling each number to a new array called double
.
This approach is considered imperative since we are deliberately looping through each number in the array and pushing the result of the doubling to the new array. The same task is accomplished, but the code is more intricate and tedious.
Solid utilizes the declarative approach to programming in various areas to make it more user-friendly and easy to understand. This approach emphasizes on stating what the desired outcome is, rather than how to achieve it, making it less complex and faster to learn and use.
2. Vanishing Components
Without taking updates into account, structuring your components is challenging enough. Updates in Solid are handled independently from components. Component functions are only ever called once before disappearing. Components exist to organize your code, not deal with updates or re-renders. Here's a quick diagram of what this process looks like:
3. Read/Write Segregation
When building systems, having precise control and predictability over data leads to an improved developer experience (DX) while using those systems. To enforce unidirectional flow in these systems, we don't need complete immutability, but rather just the ability to control who can or cannot write to or modify the data.
Solid does this through the implementation of it's primitives. Examples of these primitives are createStore
, createSignal
, and more.
Let's take a look at an example of what we mean by Read/Write Segregation.
js
const [name, setName] = createSignal("");const valueOfName = name(); // 👈 gettingfunction setValueOfName(text) {setName(text); // 👈 setting}
js
const [name, setName] = createSignal("");const valueOfName = name(); // 👈 gettingfunction setValueOfName(text) {setName(text); // 👈 setting}
In the above code snippet we're making use of one of Solids primitives, createSignal
. In short, invoking this primitive creates a reactive value; and the two things returned from calling this primitive are the getter and the setter. Take note that name
(the getter) is separated from setName
(the setter). This is just one of the ways Solid segregates things.
4. Simple Is Better Than Easy
Using explicit and consistent conventions, even if they require more effort, is beneficial for building robust systems. This is an important lesson in fine-grained reactivity. Solid aims to provide minimal tools that serve as a foundation for further development. This aligns to the reason why Solid adopts a more declarative approach rather than an imperative one.