SolidJS has gained lots of popularity lately due to having a close relationship with React. It has a declarative nature like React, useState and useEffect like hooks, JSX, ContextAPI, Portals, Error Boundaries. And it gets even better; Solid is much faster in terms of execution and has a lot smaller bundle size. Because it does not carry the burden of Virtual DOM, which means SolidJS uses real DOM instead. When your state changes, SolidJS updates only the code that depends on it.
I built the same app with minimal dependencies, Axios for fetch requests and TailwindCSS for styling. Thanks to core API similarities in both libraries. Before creating this app, I haven't yet had a chance to try Solid. So, I built the app as if I'm using React. Beware, this article does not aim to teach React, or Solid only tries to point out the differences and similarities in both libraries. Let's get started.
SolidJS App Github Link
ReactJS App Github Link
React
const fetchEpisodes = async (optionalUrl?: string) =>
axios.get<EpisodeResponse>(optionalUrl ?? 'https://rickandmortyapi.com/api/episode');
const App: FC = () => {
const [episodes, setEpisodes] = useState<EpisodeResponse>();
const [ref, inView] = useInView({ triggerOnce: true });
const fetchMoreEpisodes = async () => {
//Fetching episodes with axios
};
useEffect(() => {
if (inView === true) fetchMoreEpisodes();
}, [fetchMoreEpisodes, inView]);
useEffect(() => {
fetchEpisodes().then((res) => setEpisodes(res.data));
}, []);
return (
<div className="flex justify-center items-center flex-col p-10">
<h2 className=" font-medium text-4xl my-5">Rick and Morty</h2>
<div style={{ width: '1000px' }}>
{episodes?.results.map((episode, index) => (
<EpisodeWrapper
episode={episode}
key={episode.name}
viewRef={index === episodes.results.length - 1 ? ref : undefined}
/>
))}
</div>
</div>
);
};
export default App;
Solid
const fetchEpisodes = async (optionalUrl?: string) =>
axios.get<EpisodeResponse>(optionalUrl ?? 'https://rickandmortyapi.com/api/episode');
const App: Component = () => {
const [episodes, setEpisodes] = createSignal<EpisodeResponse>();
const fetchMoreImages = async () => {
//Fetching episodes with axios
};
const handleScroll = () => {
if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
fetchMoreImages();
}
};
createEffect(() => {
window.addEventListener('scroll', handleScroll);
});
onMount(async () => {
setEpisodes((await fetchEpisodes()).data);
});
onCleanup(async () => {
window.removeEventListener('scroll', handleScroll);
});
return (
<div class="flex justify-center items-center flex-col p-10">
<h2 class=" font-medium text-4xl my-5">Rick and Morty</h2>
<div style={{ width: '1000px' }}>
<For each={episodes()?.results} fallback={<p>Loading...</p>}>
{(episode) => (
<div>
<EpisodeWrapper episode={episode} />
</div>
)}
</For>
</div>
</div>
);
};
export default App;
Apart from some syntactic differences they are pretty much the same. In Solid we use useSignal hook instead of useState hook. Only difference between these hooks, in useState we can directly call the episodes
, but in useSignal we have to invoke it just like a function, because it's a function. If we are using Typescript we can give generic type to our signal just like we do in React.
In React we call our API's in useEffect
to supply inital data for states. But, in Solid we can either call lifecycle method called onMount
or you can ditch, onMount
and use createResource
hook. This hook works like a custom fetch — useFetch — takes a function and returns a promise, loading and error status. But, for the sake of ease
I'll go with onMount
.
To handle side-effects in Solid we have a hook called createEffect
this particular hook quite similar to useEffect
but it has some quirks. Instead of taking dependencies manually
it automatically binds itself to state inside that causes changes. Example:
function Counter() {
const [count, setCount] = createSignal(0);
const increment = () => setCount(count() + 1);
createEffect(() => {
console.log(count()); // Logs count every time it changes
});
return (
<button type="button" onClick={increment}>
{count()}
</button>
);
}
Going back to our original example. So, we want to run handleScroll
each time person scrolls. We create createEffect
and call our event listener. That's it. For the return part, in React we generally use map to iterate over the state, but it Solid we have a built in option called For
. It's actually a component which receives each
in our case it's episodes
state and fallback
option to show loading or anything you want. And, good part is you don't have to deal with keys in Solid it automatically handles it for you.
By the way, you can pass props just like you pass props in React everything is the same.
Benchmarks
Benchmarks criteria will be performance profiling in Chrome Dev Tools and final bundle sizes. Let's start with Performance profiling. The performance tab shows an overall breakdown of CPU activity into four categories:
- Loading: Making network requests and parsing HTML
- Scripting: Parsing, compiling, and running JavaScript code, also includes Garbage Collection (GC)
- Rendering: Style and layout calculations
- Painting: Painting, compositing, resizing and decoding images
The left side is React, and the right is Solid. As you can see Scripting part is almost 3x faster, Rendering almost 2x faster, Painting part is abnormally faster.
If we went down a level deep on the scripting part, we see why.
React
Solid
React first makes a Function Call which evaluates and commits VDOM into DOM, then makes the XHR calls. Since Solid does not have to deal with VDOM to DOM, it skips that part and starts requests right away. By the way, if you are wondering about what Functional Call and XHR Load, means you can check this site Event References.
Bundle sizes of apps:
React
Solid
Conclusion
SolidJS definitely doing some things or maybe most of the things better than React, but in my humble opinion, the biggest problem for Solid is the ecosystem. React has an enourmous ecosystem it has components, hooks, patterns for everything. Think something and try serching that thing in npm, and I bet you will find something regarding your needs. Right now Solid's selling point is being fast. In benchmarks it says
it is quite close to vanilla JS.
It is close to vanilla JS, but we are missing the key thing here. People are not going with React because it is fast, and people even know it isn't. They are going with React because of the massive community and tooling ecosystem around it. But I believe that SolidJS has a bright future and, as the community gets bigger and bigger, it'll be even better.
Top comments (3)
To be fair, this is comparing but one use case. If you are dependant on certain amenities, like material UI, input mask, or custom select handlers, you're currently out of luck in Solid. There are also no browser extension dev tools.
On the other hand, you can use styled components, tailwind or similar css frameworks, or create your own components. The current lack of libraries also means that the one you're searching for is not buried under 1000 other mediocre ones. And since components are evaluated only once and only effects and memos run on change, you can use the browser dev tools all right. Not to forget we're catching up fast.
Also, react is based on immutable reactivity, meaning that changes have to propagate from the root to the top, whereas Solid allows for granular reactivity, meaning changes only cause effects to re-run when and where they occur without parent components ever noticing unless tracking the value themselves.
Last not least, the community around Solid is a big part of what makes it great. If you join discord, chances are that your questions will be directly answered by the developers. Also, the project is open to PRs without going through a lot of paperwork first (thanks, Facebook).
I don't think anyone has any illusions on the ecosystem side of things. This is the first concern always. The performance is impressive, but one can always think of ways to wrestle out even more performance if desired.
The key value of Solid is that it can take the tools, syntax, and APIs that you are familiar with, take the flexibility of runtime javascript and composition, and embrace a reactive execution model. This example was pretty much identical on both sides, but as components scale in complexity React Hooks get trickier.
People have been enjoying this in Vue and Svelte for some time now, but Solid has brought that simpler model to React's structured philosophy. The result is something that is performant and requires less logic, but also with explicit control and transparency we love from React.
I’ve been experimenting with Svelte for a while now. Svelte probably has more of a community around it than Solid, but obviously still a far cry from the size of the React community. I’d be interested in seeing the performance difference between Solid and Svelte. Overall I think these frameworks that are faster ultimately will win out, but it will take a while.