Solidjs and React.js — Difference and Comparison
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 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 of Solid.js 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.
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 a state(signal) using createSignal hook. createSignal takes the default state(signal) as a parameter and returns an array of state(signal) and state(signal) setter functions.
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 the 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
React.js state management using signals
useAsync hook with cache (devsmitra.blogspot.com)