batch
functionOne of the most pressing challenges that all frameworks aim to improve upon is state and reactivity management, as seen by developments made to frameworks and libraries like SolidJS, React, Svelte, Angular, and Vue.
Batching state updates is one way that frameworks attempt to improve upon their reactive models. Instead of re-rendering the UI in response to each individual state change, frameworks allow developers to specify what changes are related so that UI updates are delayed until all the related values are changed.
In React 18, this problem was tackled with the automatic batching feature, which improved upon batching to include events, asynchronous events, and Hooks. This behavior is automatic and would require you to use the flushSync
method to prevent it.
Though it’s been around for a while, Solid has recently made updates to its batch
function, which allows developers to manually decide when to batch or not depending on their particular app’s needs. In this article, we’ll explore how it works.
Solid is a frontend framework that provides several benefits over alternatives like Angular, Vue, and React.
Like Svelte, Solid is compiled, so instead of shipping an entire framework to each end user, the code is compiled and turned into plain Vanilla JS. Therefore, you’re only shipping the end user the code necessary for much smaller bundles.
Like React, Solid uses JSX as a way of expressing UI. In Solid, a reactive value is called a signal, and an operation that should run anytime those values change is called an effect.
To create a signal, we use createSignal
, which is similar to useState
in React. To create an effect, we use createEffect
. However, the JSX returned by the component is automatically treated like an effect.
This is the opposite of React, where a component function runs in its entirety each time the state changes. In Solid, only the code explicitly designated inside effects will repeat on state updates. So, instead of using useEffect
in React to specify code you don’t need to run on every update, in Solid, code only runs on updates if you wrap the code in a createEffect
.
batch
?To try out this example, you can clone the code from the main branch of this repo. All of the relevant code is in the /src/App.jsx
below:
import logo from './logo.svg'; import styles from './App.module.css'; import {createSignal, createEffect} from "solid-js" function App() { const [p1, setP1] = createSignal("Alex Merced") const [p2, setP2] = createSignal("Tony Merced") let p1Input let p2Input createEffect(() => console.log(p1(), p2())) return ( <div class={styles.App}> <header class={styles.header}> <h1>Player: {p1}</h1> <h1>Player: {p2}</h1> </header> <form onSubmit={(event) => { event.preventDefault() setP1(p1Input.value) setP2(p2Input.value) }}> <input type="text" placeholder="player 1" name="p1" ref={p1Input}/> <input type="text" placeholder="player 2" name="p2" ref={p2Input}/> <input type="submit"/> </form> </div> ); } export default App;
We have two signals: reactive values p1
and p2
. These two values are both displayed in the UI as h1
. To show how they change, we created an effect that logs them both to the terminal.
There are two inputs in the form. When the form is submitted, the signal’s value is set to the value of these inputs individually. Here, we see something unique happen. Let’s say you enter Bread
in the first input and Cheese
in the second input. When you submit the form, you’ll see the following console logs:
Bread Tony Merced Bread Cheese
When we change p1
on line 20, it triggers all the effects that depend on that value to rerun UI updates and effects with the two console logs. Then, when p2
is changed, this whole thing happens again, hence the second log.
In the end, the resulting UI really depends on both their values. For efficiency, you should wait for both values to be updated to re-run all dependent effects, which is where batch
comes in.
batch
in SolidTo see the example code, you can clone this branch of the repository. Let’s say we have the code below in our src/App.jsx
file:
import logo from "./logo.svg"; import styles from "./App.module.css"; import { createSignal, createEffect, batch } from "solid-js"; function App() { const [p1, setP1] = createSignal("Alex Merced"); const [p2, setP2] = createSignal("Tony Merced"); let p1Input; let p2Input; createEffect(() => console.log(p1(), p2())); return ( <div class={styles.App}> <header class={styles.header}> <h1>Player: {p1}</h1> <h1>Player: {p2}</h1> </header> <form onSubmit={(event) => { event.preventDefault(); batch(() => { setP1(p1Input.value); setP2(p2Input.value); }); }} > <input type="text" placeholder="player 1" name="p1" ref={p1Input} /> <input type="text" placeholder="player 2" name="p2" ref={p2Input} /> <input type="submit" /> </form> </div> ); } export default App;
In the code snippet above, we added the import of batch
on line 3, and we wrapped the two value updates within a call to batch
on line 19.
If you fill in the inputs with bread
and cheese
once again, you’ll only see one console log after hitting submit:
bread cheese
batch
delayed running effects until all the state updates within the batch
callback were completed. This reduced the number of times the effects in our code were run, resulting in more efficient code overall.
batch
?In early versions of your application, you might not bother using batch
, instead just focusing on building a functional app. But, as you app matures and you need to optimize performance, batching state updates, memoizing complex calculations, and other techniques can really help to make your app run as smoothly as possible.
Bottom line, if you’re updating several unique signals, but you don’t want to run the effects until they are all done updating, use batch
.
Batching is useful because it prevents redundant operations for a crispier app. While React takes the approach of assuming you always want batching, Solid gives you tools to more easily express your intended outcome and batch only when you need to, and not when you don’t. I hope you enjoyed this article, and be sure to leave a comment if you have any questions. Happy coding!
There’s no doubt that frontends are getting more complex. As you add new JavaScript libraries and other dependencies to your app, you’ll need more visibility to ensure your users don’t run into unknown issues.
LogRocket is a frontend application monitoring solution that lets you replay JavaScript errors as if they happened in your own browser so you can react to bugs more effectively.
LogRocket works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app’s performance, reporting metrics like client CPU load, client memory usage, and more.
Build confidently — start monitoring for free.
Angular’s new `defer` feature, introduced in Angular 17, can help us optimize the delivery of our apps to end users.
ElectricSQL is a cool piece of software with immense potential. It gives developers the ability to build a true local-first application.
Leptos is an amazing Rust web frontend framework that makes it easier to build scalable, performant apps with beautiful, declarative UIs.
Learn more about the 5 best JavaScript libraries for dealing with multidimensional arrays, such as ndarray, math.js, and NumJs.
2 Replies to "Understanding SolidJS’ updated <code>batch</code> function"
Hi Alex, great article! I just wanted to mention that the batch function is not new, Solid actually had it for a long time.
You’re right, Solid has had this function for a while. The point of this post was to highlight some of the recent updates to batch, so we’ve made a couple changes to make that a bit clearer. Thanks!