Project Setup and Initial Cleanup
SolidJS is gaining a lot of traction lately. It is awesome as I show you in another video. And therefore, let's dive into it and let's get started with it.
Getting started is quite straightforward. It's that command here which you can execute in your terminal to create a new SolidJS project, so that's what I'll do. And once this command executed, you'll have a SolidJS project folder which you can, of course, open with any code editor of your choice. Here, I'm using VS Code.
Now, as a first step in this new project, we need to install our dependencies because that was not done automatically when we created the project. And then what you get is a Vite project with a folder structure that's quite similar to React projects no matter if you created them with Vite or Create React app.
We got a index.html file here in our root folder in this case here. And this index.html file is pretty empty as you know it from these kinds of frameworks where we only have our entry point and then we got a couple of JSX files in the source folder and it is the source folder in which we will spend the majority of our time.
Now, the index.jsx file is the main entry point of this application. And in that file, you again see some code that looks a lot like React, not exactly like React, but very similar. We got a render function imported from solid-js/web. We're executing it and passing a function to it and that function returns the App component as JSX code. And we also tell this render function where to insert this app component in our index.html file so that it is in the end rendered here in place of this div.
Now that's the index.jsx file. The App thing here which is imported from App.jsx is coming from this file. And in there, we got a component function because SolidJS, and that's really important when you're learning it, is quite similar to React. If you worked with React before, learning SolidJS will be a breeze.
Now in this app component function, we got a bunch of JSX code. We got a CSS module import because this project supports CSS modules. And I also have the index.css file which is imported in index.jsx for some global styling.
Now for a start, I'll delete the App.module.css file. I will also clear the logo.svg file because I don't need it here. And I'll remove these two imports from App.jsx. And then also clear all that JSX code from the app component here. And instead for the moment, we can just output Hello world! here like this. So that's the cleaned up app component.
I did not change the index.jsx file, but I do wanna change those global styles and I prepared some CSS code for that. And to make sure that we all have that same starting point, you find my updated starting project below the like button so that we can all use exactly the same starting project.
So with that, what we got is a very simple SolidJS application, which looks very similar to React.
Creating Your First Component
And if we wanna run our development server, we can do that with help of the dev script. So we can run npm run dev and this will start a development server and we then find our application on local host 3000.
Now, as mentioned in my SolidJS overview video, and as you can see in this project, SolidJS has a lot of similarities with React. You do, for example, create component functions that return JSX code. And, of course, we can create an additional component. Here, I'll do it in the components folder. And in there, I wanna create a Header.jsx file so that in there, I have some header which is on top of the page.
Now in that header.jsx file, just as in React, we can create a Header component, so a functional component, and SolidJS doesn't have class-based components just in case you're asking. And we can export this component function. We should start with a capital character as is the convention for component function just as is the case in React. And then in there, we can return our header. And here, I'll give it an id of main-header just to make sure that my global styling styles this header because I got some CSS rules for it. It is main-header id here.
And then in there, we can also add a image, which I'll import and add soon, which will be my SolidJS Logo. I don't have the image yet, but soon we'll have it. And then maybe an h1 element where we say SolidJS Basics. So a very simple component which doesn't do anything fancy, doesn't take any props though SolidJS supports that feature, doesn't manage any state, just a regular component so that we can see that we can build such components which look like React components in SolidJS.
Now, of course, we want an image. And if you used the starting project you find below the video, you already got a image in your assets folder. Otherwise, you can now take a look at it and download that image from there and add it to your assets folder. And then since it's in that assets folder, you can just import this solidLogo from and then from the assets folder and then there, it's this solidjs-logo.png file. So you can import static assets like this with a regular import statement. And the Vite project behind the scenes will make sure that the actual path to the image is created instead. And then here for the source of that image, we can now use the single curly braces opening and closing, again just as we do it in React, to set some dynamic value as a value for this source property here and set this to solidLogo.
So again here, we got another React similarity, but no worries. There also will be some differences. With that header component added, of course, in the app component, we can import the Header component from components/Header. You can omit the file extension here. And then here, I'll replace my JSX code of the app component with this special fragment component, which again you might know from React because soon, I'll have multiple sibling components here returned by the app component in the app components JSX code. And just as in React, it's not allowed to have multiple sibling components in JSX or multiple sibling elements in JSX unless you wrap them by such a fragment, which is why I'm doing this here. Then here, we can render the Header component as a self-closing component like this.
With that done, if you save all files, you should see this header here on the screen. So that's a first basic component, not too fancy, nothing special, looks like a React component. And indeed, you could use it like this in a React application as it turns out.
State Management with createSignal
Now back in the app component, I wanna dive into something, some concept which is different though and that would be state management. Of course, you have state in React as well, but the way you manage it, the way it's handled internally is totally different when using SolidJS.
Now here, I wanna build a very simple counter app, which means I wanna have a div with an id of actions let's say where I simply have two buttons. And the first button decrements the counter, the second button increments it. Of course, not a super fancy app, but good for diving into all these core concepts. So we got these two buttons and above the buttons, I'll add a paragraph here where I wanna output the current counter value. I'll give it an id of counter for styling reasons just as this div has an id of actions for styling reasons.
And then here, I wanna output counter value, which soon will be dynamic. Indeed, that counter value will be the state which I wanna manage, which should be changed by these two buttons and which should then be reflected here by value. Now in React, you would create state with useState with the useState hook. Here in SolidJS, you instead import something from SolidJS and that something which you import is a function called createSignal.
Now, createSignal is then called just as useState would be called here in the component function. You can pass some initial state value to it like zero for the initial counter state. And then what you get back, just as with React, is an array with two elements, exactly two elements, and the first one will be your state value and the second one will be a function you can call to update that value. So again, still React, right? But didn't I say that it would be different here? Yes, it is. It looks like React up to this point, but it will be different. No worries.
So we got this function, we got the current counter value and I wanna output the counter value here. And for that, we use the curly braces. And now here's the first difference. We do not type counter like this. Instead, we call it as a function. That's important. That's how you access the state value in SolidJS. You call these state values as functions and that gives you access to the state. Now, this is also required because internally, SolidJS uses a totally different reactivity system. I do talk about that in my other SolidJS video, which you definitely should watch to get more details about SolidJS.
But the core idea is that unlike with React, you don't have a virtual DOM. SolidJS does not use a virtual DOM. It does not compare different virtual DOM snapshots. Instead, it memorizes the places in the real DOM where you use state. And when you then later update the state, it will go exactly to these places and update just these places so it doesn't need to compare any different DOM snapshots. Instead, it knows where dynamic values that might change are being used, and it then goes directly to those places when those values change and it goes nowhere else, just to these places.
It, therefore, also only calls your component functions once and then basically compiles that JSX code to the real DOM. And unlike with React, your component functions are therefore not called every time the state changes, but only once. And when you then do change the state, it as mentioned goes directly to the real DOM to the place where the state is used. So a totally different reactivity system. And by calling this function here, we're basically telling SolidJS that this is a place where we are using a dynamic value that might change and that it should memorize this place, in this case here, to reflect the counter value and update it whenever the counter changes.
Updating State and Handling Events
So that's what we're doing here. And now to change the counter, we can go to our buttons and add the onClick listener just as we could do it with React. Though in SolidJS, we can also write onclick like this, all lowercase if you want to. There are some differences regarding the HTML attributes and this is one of them. You can use onClick like this or onclick like this, whatever you prefer. Here, I'll use this approach to show you these differences.
And then here between these curly braces, you can point at a function that should execute when that click occurs or you create an anonymous function here and then here I call setCounter. And now for updating the counter, I wanna access the current count value. And then for this button, deduct one. And there are two ways, two valid ways of doing this here. The first approach is to again call counter to get access to the current state value, you may do that, and then deduct one from that value. And the second approach, which I'll show you on the second button here, is to pass a function to this state updating function just as you might know it from React. And in this function, you automatically get the previous counter value from SolidJS and you then return the updated value like this by adding one to it. And with that, we also got the code for updating the state in place. We're then also using the state here. And now if we save everything, we can therefore go back and press these buttons to manipulate the state and see that state reflected on the screen as we press the buttons.
So as you can see, writing that code isn't too difficult, especially if you have a React background. It's quite similar. But as mentioned, under the hood, it behaves quite differently. And you can see that it behaves differently by console logging here in the app component, for example, outputting app component here. And what you'll see if you do that and you then open your developer tools is that if you reload, this executes once. But if I press these buttons, it does not execute again. And that would be very different for React. There, you would get a new log output every time you press such a counter button. Here for SolidJS, that's not the case. And since that's not the case, you can also do things like calling fetch here to send a request when that component is first rendered and then update the state once you got some data, or you could set a timer with setTimeout, or an interval with setInterval.
And here in the interval, we could then, for example, update the counter every second by again calling counter plus one here with the setCounter function. If you do that and saved this, you don't create an infinite loop as you would do it with React. Instead, this just works and the counter is now magically updating on its own. We can, of course, still manipulate it, but it will have that interval going. And in my opinion, that's, of course, a great thing. It simplifies the mental model for us developers because we don't have to work with user fact and keep in mind that component functions execute every time we update state. We don't have to implement complex optimizations to avoid component function re-execution if we know that they shouldn't, but React doesn't. This is all not needed here with SolidJS. Instead, we can just safely run code in the component function and it will only execute once. We don't have to worry about anything else regarding that.
Managing Side Effects with createEffect
And, of course, as also mentioned in my SolidJS overview video, this also ensures that SolidJS is super performant because it only updates the parts in the DOM that need updating. It doesn't do any comparisons before going ahead and doing that update. It doesn't need those extra virtual DOM comparisons.
So that was setInterval which you could safely use as shown, but sometimes you, of course, also might have code that should execute every time some signal value changes. And the component function, as mentioned, doesn't execute over and over again, but that's why SolidJS offers you a createEffect function, which can be imported. createEffect is quite straightforward. You execute it in your component function to register the effect so to say and you then pass a function to it, for example, an anonymous arrow function. And in there, you can have your Effect code. Here, I'm just logging something to the console, but we could also be sending an HTTP request here, for example, to send some data to some backend analytics service.
Now here, I'll execute this Effect because counter updated and to ensure that this Effect function executes whenever the counter value changes, I have to use the counter value in there, for example, to output it here. If you use a signal value in an Effect function created with createEffect, SolidJS will also memorize that and re-execute this Effect function whenever the signal value used in there change. And for that reason, you will see it runs initially. And then every time I click the button, this code from the Effect function is executed and only that, not the component function, just the Effect function code. So Effects are another very useful feature offered by SolidJS.
Creating Computed (Derived) Values
Now, another common use case is that you might have computed values and those are also quite straightforward to set up.
If we wanna have a doubleCounter here, we can create a concept of that name and now you could think that you simply multiply counter by two, but that would not work because first of all, you need to call this as a function, but even that would not work because you must not forget that the component function only executes once. So this would only execute once.
Now, to make sure that you have a true computed value that changes whenever the counter changes, you should wrap this into a function step like this so that I have an anonymous function that returns the result of multiplying counter by two. And then you can use your computed value just as a state value anywhere in your code as a function. That's important, you have to execute it as a function, and that then again will make sure that SolidJS remembers that place in the DOM and updates it with the, in this case, computed value whenever the signal values the computed value depends on change. So it will automatically track the changes of counter. And whenever counter changes, it will recalculate the computed value and will then update it in the DOM.
And therefore with that, if I call this now, I got the doubleCounter being output here. Here in the Effect, I still have the normal counter value which was not doubled because in the Effect, as you might recall, I am just referencing that normal counter, not the doubled version, not the computed value. So that's how you can use computed values.
Using Props and Maintaining Reactivity
Now, the last core concept which you use all the time which I also wanna show you would be the usage of props. Let's say that this counter output should be in its own component. For that, I'll cut it from the app component. And in the components folder, we can add a new counter.jsx file or anything like this, name it counter and, of course, also export it just as we did with the Header component before. And then here, I return this JSX code.
Of course, here, I can't use this state value now though, this signal value, because I don't have access to the signal here. It's in the app component after all. Now, we can use props for that just as you would in React. And we could then, for example, output props.value. The prop name, of course, is up to you. And there also is a special children prop just as in React to output all the content that might be passed between opening and closing tags of your own component. Here, we don't need that though. Instead, I'll use a prop of the name value. But again, any name could be used here.
What's important though is that you don't use object destructuring here. You could do that in React. You can't do it in SolidJS. If you use object destructuring for your props object, you break SolidJS reactivity for that props object, which means it won't know if the value, if a prop value changed, and therefore it won't update it in the DOM. So if you use object destructuring on the props object, the reactivity for this component will be broken. That's why you must not use object destructuring. Instead, you should use the props object and then use props dot here in your JSX code to ensure that the reactivity stays intact, but that's the only thing to watch out for. With that, we got the props here.
And now back in the app component, we can import our counter component here, set the value prop and set it to counter or double counter, whatever you want. And again, of course, the signal value must be executed as a function here to make sure that we do get the actual value and that SolidJS memorizes this place in the DOM. With that, if I reload, this still works as before, but now with help of that separate component and props.
Overview of Other Core Features
And that's it for this basic SolidJS application. Now SolidJS, of course, has more to offer. It has a built-in For component to make it easy for you to output list data so that you can simply loop through items and render different JSX elements for every item. It has a show component to render content conditionally based on whichever conditions you need. It also supports refs, which are in SolidJS case simple variables that you assign to the ref prop of any element or component of your choice. And it also has a createResource function built in which you can use to create asynchronous signal values where you can conveniently execute some asynchronous code with async await like sending an HTTP request. And the return value of that function would then be set as a value for that signal which is created by createResource. And you could then use this signal value like any other signal value anywhere in your JSX code.
So a bunch of really nice features, everything you need to build simple or complex applications. And as you saw in this video as well, it's really easy to learn if you worked with React before, but it offers some distinct advantages.