Solidjs and React.js - Difference and Comparison
Rahul Sharma
Posted on May 30, 2022
Solidjs: Solid is a declarative JavaScript library for creating user interfaces. Instead of using a Virtual DOM, it compiles its templates to real DOM nodes and updates them with fine-grained reactions.
React: React is a JavaScript library for building user interfaces. It uses Virtual DOM to efficiently update and render just the right components when your data changes.
Key features of Solidjs:
- Fine-grained updates to the real DOM
- Render-once mental model: your components are regular JavaScript functions that run once to set up your view
- Automatic dependency tracking: accessing your reactive state subscribes to it
- Provides modern framework features like JSX, fragments, Context, Portals, Suspense, streaming SSR, progressive hydration, Error Boundaries, and concurrent rendering.
Key features of React:
- Virtual DOM: React uses a virtual DOM to efficiently update and render.
- Provides modern framework features like JSX, fragments, Context, Portals, Suspense, streaming SSR, progressive hydration, Error Boundaries, and concurrent rendering.
- Maintained by Facebook and the community.
Side by side comparison Solidjs vs React(functional component)
Components:
React:
React components can be created using class-based syntax or function-based syntax. Components are functions that return JSX.
// Function-based syntax
const Hello = () => <div>Hello</div>;
Solidjs:
Components are functions that return JSX.
const Hello = () => <div>Hello</div>;
Note: Solidjs and React both use the same JSX for templates.
State: State is a plain JavaScript object that is used to record and react to user interactions.
React:
A state is a plain object. You can create a state using the useState hook. useState takes the default state as a parameter and returns an array of state and state setter functions.
const Counter = () => {
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
// OR
const increment = () => setCount((c) => c + 1);
return (
<div>
<h1>{count}</h1>
<button onClick={increment}>Click</button>
</div>
);
};
Solidjs:
You can create state(signal) using createSignal hook. createSignal takes default state(signal) as an parameter and returns array of state(signal) and state(signal) setter function.
const Counter = () => {
const [count, setCount] = createSignal(0);
const increment = () => setCount(count() + 1);
// OR
const increment = () => setCount((c) => c + 1);
return (
<div>
<h1>{count()}</h1>
<button onClick={increment}>Click</button>
</div>
);
};
NOTE: React Hooks can only be called inside the root of the component. Solid createSignal can be used outside of a component.
const [count, setCount] = useState(0); // Not allowed
useEffect(() => {}, []); // Not allowed
const Counter = () => {};
const [count, setCount] = createSignal(0); // Allowed
createEffect(() => {}); // Allowed
const Counter = () => {};
Effects(side effect): It's a function that runs when state changes.
React:
In React we have to pass the dependencies array to the useEffect hook.
There are 3 ways to do it:
- Without dependencies array (the effect will be called on every render)
- With dependencies array (the effect will be called only when dependencies change)
- With empty dependencies array (the effect will be called only once)
const Counter = () => {
const [count, setCount] = useState(0);
useEffect(() => {
console.log('I am called on every render');
});
useEffect(() => {
console.log('I am called only when count changes');
}, [count]);
useEffect(() => {
console.log('I am called only once');
}, []);
return ...
};
Solidjs:
In Solidjs we don't have to pass dependencies array like the useEffect hook. It'll automatically detect dependencies and call effect only when dependencies change.
const Counter = () => {
const [count, setCount] = createSignal(0);
createEffect(() => {
console.log('I am called only once');
});
createEffect(() => {
console.log('I am called only when count changes',count());
});
return ...
};
Lifecycle: It helps to monitor and manipulate the state.
React:
const Counter = () => {
useEffect(() => {
console.log('I am called onMount');
return () => console.log('I am called onUnmount');
}, []);
return ...
};
Solidjs:
const Counter = () => {
onMount(() => console.log('I am called onMount'));
onCleanup(() => console.log('I am called onUnmount'));
return ...
};
Refs: It's a way to access DOM elements.
React:
const Counter = () => {
const ref = useRef();
useEffect(() => ref.current.focus(), [ref]);
return <input ref={ref} />;
};
Solidjs:
const Counter = () => {
let ref;
onMount(() => ref?.focus());
return <input ref={ref} />;
};
Props: It's a way to pass data to components. It's a plain JavaScript object.
React:
Props are passed as an object and can be destructured.
const Counter = (props) => {
return <div>{props.count}</div>; // Valid
};
const Counter = ({ count }) => {
return <div>{count}</div>; // Valid
};
Solidjs:
Props are passed as an object and can't be destructured.
const Counter = (props) => {
return <div>{props.count()}</div>; // Valid
};
const Counter = ({ count }) => {
return <div>{count()}</div>; // Not Valid
};
List of Components/Elements:
React:
For multiple lists of data to be rendered, we can use the map
function.
const Counter = () => {
const list = [1, 2, 3];
return (
<div>
{list.map((item) => (
<div>{item}</div>
))}
</div>
);
};
Solidjs:
For multiple lists of data to be rendered, we can use the map
function or For component.
const Counter = () => {
const list = [1, 2, 3];
return (
<>
{list.map((item) => (
<div>{item}</div>
))}
<For each={list} fallback={<div>Loading...</div>}>
{(item) => <div>{item}</div>}
</For>
</>
);
};
Conditional Rendering: It's a way to render a component based on condition.
React:
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<h1>{count < 5 ? "True Value" : "Falsy Value"}</h1>
<button onClick={() => setCount(count + 1)}>Click</button>
</div>
);
};
Solidjs:
const Counter = () => {
const count = 5;
return (
<div>
<h1>{count < 5 ? "True Value" : "Falsy Value"}</h1>
// OR
<Show when={count < 5} fallback={<h1>Falsy Value</h1>}>
<h1>True Value</h1>
</Show>
</div>
);
};
Note: Solidjs doesn't rerender the component. It'll always render the first evaluated value.
const Counter = () => {
const [count, setCount] = createSignal(0);
const TrueCase = (
<div>
<h1>From True Value </h1>
<button onClick={() => setCount((c) => c + 1)}>Click {count()}</button>
</div>
);
const FalseCase = (
<div>
<h1>From False Value</h1>
<button onClick={() => setCount((c) => c + 1)}>Click {count()}</button>
</div>
);
if (count() < 5) return TrueCase;
return FalseCase; // Never render this
};
// Solution:
const Counter = () => {
const [count, setCount] = createSignal(0);
const TrueCase = (
<div>
<h1>From True Value </h1>
<button onClick={() => setCount((c) => c + 1)}>Click {count()}</button>
</div>
);
const FalseCase = (
<div>
<h1>From False Value</h1>
<button onClick={() => setCount((c) => c + 1)}>Click {count()}</button>
</div>
);
return (
<Show when={count() < 5} fallback={FalseCase}>
{TrueCase}
</Show>
);
};
Context: It's a way to share data between sibling/child components.
React:
const CountContext = React.createContext(0);
const Provider = ({ children }) => {
const [count, setCount] = useState(0);
return (
<CountContext.Provider value={{ count, setCount }}>
{children}
</CountContext.Provider>
);
};
const Counter = () => {
const { count, setCount } = useContext(CountContext);
return <h1 onClick={() => setCount((c) => c + 1)}>{count}</h1>;
};
const App = () => {
return (
<Provider>
<Counter />
<Counter />
</Provider>
);
};
Note: use can use context with useReducer, Instead of directly calling setCount.
Solidjs:
export const CounterContext = createContext([{ count: 0 }, {}]);
export function CounterProvider(props) {
const [state, setState] = createStore({ count: props.count || 0 });
const store = [
state,
{
increment: () => setState("count", (c) => c + 1),
},
];
return (
<CounterContext.Provider value={store}>
{props.children}
</CounterContext.Provider>
);
}
const Counter = () => {
const [state, { increment }] = useContext(CounterContext);
return <h1 onClick={increment}>{state.count}</h1>;
};
const App = () => (
<CounterProvider>
<Counter />
<Counter />
</CounterProvider>
);
Solid offers many more features like a store for state management check the API doc for more info.
Live Demo: Counter Demo
Thank you for reading 😊
Got any questions or additional? please leave a comment.
Must Read If you haven't
useAsync hook with cache
Getting started with SolidJs – A Beginner's Guide
React best practices and patterns to reduce code
3 steps to create custom state management library with React and Context API
How to cancel Javascript API request with AbortController
13 Typescript Utility: A Cheat Sheet for Developer
More content at Dev.to.
Catch me on YouTube, Github, Twitter, LinkedIn, Medium, Stackblitz, Hashnode, HackerNoon, and Blogspot.
Posted on May 30, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.