Tiny Atom 3.0.0

Karolis Narkevičius
4 min readAug 3, 2018

--

Tiny atom is a JavasScript store modified via actions (aka redux alternative). It’s small, comes with batteries included and exposes a compact action API.

Tiny Atom 3 ships with:

  • optimized connectors
  • improved state logger
  • preact/react debug mode for detecting unnecessary re-renders

🎉

Optimized connectors

The original tiny atom encouraged re-rendering the entire application on each change relying on virtual DOM’s efficiency. This matched React’s mental model well and kept things simple:

atom.observe(render)

However this is not always enough. In larger applications or mobile devices DOM diffing can have a significant cost.

The new tiny-atom flips the approach and encourages to only render your application once leaving the heavy lifting to connect , which now subscribes to atom changes directly and re-renders only the relevant parts of the application. The connector uses a series of strategies to keep things efficient and perform the least amount of work possible.

First, connect defers the re-rendering to the next animation frame — you don’t need to render more than once per animation frame. And if you want to opt out of this in specific cases (e.g. when handling input field changes), you can set the sync: true option when connecting that particular component.

Second, connect avoids rendering nested components if their ancestor components already re-rendered due to a state change. This might become the default behavior in React in the future once all `setState` calls are batched, but for now, this has to be done at the library level.

And finally, connect implements a componentShouldUpdate hook for each of your connected components and performs a shallow comparison of props. This ensures that a component and all it’s children are only rendered if the state that they depend on changed.

All in all, the new connect reduces virtual DOM diffing and re-renders to a minimum keeping your application buttery smooth.

State logger

The new bundled logger is configurable, produces cleaner output and prints the state diff after every state update. Here’s a how that looks:

It only prints updates (or mutations), the action that caused them and the state changes that that update caused. It prints what has been added, removed or changed. The logger limits the printed number of changes per mutation to 10 with the remaining changes collapsed away to keep the console from overflowing with information.

The logger is now configurable, see the default settings in this snippet:

const createAtom = require('tiny-atom')
const createLog = require('tiny-atom/log')
const log = createLog({
actions: false,
updates: true,
diff: true,
diffLimit: 10,
include: [], // white list actions - good for focus
exclude: [], // black list actions - good for removing noise
logger: console
})
const atom = createAtom(initialState, actions, { log })

Preact/React debug mode

Even when you connect your app to the store using the new optimized connect there are a few pitfalls to watch out for that could cause your components needlessly re-render. Some examples of props changing and causing re-renders are:

  • inline functions, e.g. onClick={() => dispatch('open')} , every time the component re-renders, we create a new inline function that will not match the prop equality check
  • same data, but freshly allocated array/object, e.g. items={items.slice(0, 5)} might always return the same items, but because we slice the array we pass a fresh array instance every time that will not match the prop equality check

You can now set debug prop on the Provider or individual connections, e.g.:

  • <Provider debug />
  • <Consumer debug />
  • connect(map, actions, { debug: true })

This will log information about which components re-rendered and what props caused them to re-render. It highlights the avoidable prop changes in red by comparing stringified prop values.

Summary

Many of the similar features can be found out there as standalone libraries or react/preact/redux plugins, but tiny-atom brings it all together in a self contained package make it comprehensive enough for applications of any size without the need for extras.

Tiny atom 3 introduces further improvements when compared to V1:

  • use new React.createContext under the hood
  • deep merge state updates by default
  • simplify the constructor signature to createAtom(initialState, actions, options)
  • split split into set and dispatch for clarity and to enforce the best practice of always dispatching actions from within components instead of making direct state updates

In the future versions, I’m keen to explore how selectors could be incorporated into tiny-atom as well as exposing actions as functions for better editor integration and action discoverability.

But today —take tiny-atom 3.0.0 for a spin or clone the repo to play with the examples.

npm i tiny-atom

🙏

--

--

Karolis Narkevičius

Co-founder @zeroldn. Previously — Director of Engineering @qubit. Biodegradable. Always betting on JavaScript.