Reactivity | Lucid.js

Lucid.js / Reactivity

Introduction 🔗

Lucid.js is a reactive framework. This means that as data changes, parts of the DOM that depend on it are updated automatically. In this way, it's similar to other frameworks such as React and Vue.

Lucid can be fully- or semi-reactive. It's fully-reactive by default, but can be made semi-reactive for bigger, more DOM-heavy apps, to strike a balance between reactivity and performance.

Reactive content types 🔗

Lucid has four types of reactive content - that is, parts of the output that will (or can) update automatically as and when data they depend on is changed. They are:

  • Text nodes - textual output within elements
  • Attributes
  • Conditionals - elements/child components that should or should not render based on some condition
  • Repeaters - elements/child components that should be output iteratively, N-times

Since Lucid is fully-reactive by default, all four are reactive, but it's possible to modify this - i.e. to have only some of these types be reactive - via the autoReprocess instantiation param.

Setting custom reactivity 🔗

autoReprocess is an array or boolean, specified when Lucid is instantiated. If true (which is the default), Lucid will be fully-reactive. If an array, you can specify the types of content you want to be reactive (omitting those you don't):

  • "output"
  • "attrs"
  • "conds"
  • "reps"

For example, to have only text nodes and attributes be reactive we'd use:

new Lucid({ ... autoReprocess: ["output", "attrs"], ... });

This may not always be desirable, however. For larger apps, this can impact performance, which is why Lucid is semi-reactive by default. We'll talk more about this below.

Handling semi-reactivity 🔗

As we've seen, semi-reactivity means some parts of content will update automatically as data changes, while others will not. How, then, do we update output for those that do not automatically update?

The components API has a series of methods for updating each of the four types of reactive content discussed above (each one also has a shorter alias). These are:

  • reprocessOutput() / ro() - update text nodes
  • reprocessAttrs() / ra() - update attributes
  • reprocessConds() / rc() - update conditionals
  • reprocessReps() / rr() - reprocess repeaters

Remember: these need to be used only for types of content that are not reactive, i.e. those expressly not allowed by the autoReprocess param.

The Conditionals page shows an example of how to manually reprocess a conditional, and the Repeaters page has a corresponding example for Repeaters.

If you're not sure what conditionals are or how they work, check out the Conditionals docs. Likewise Repeaters.

Performance 🔗

As already mentioned, Lucid tries to strike a balance between reactivity and performance. While it is, as we've seen, possible for full-reactivity, it's important to bear in mind perforamnce considerations when doing so.

The main concern here is with conditionals and repeaters, which each have the ability to load any number of child/descendant components.

Conditionals can mitigate this concern somewhat by using cached reinstatement.

Consider the following app structure (each hierarchical level represents a nested child component)

  • Master component
    • Child component
      • Child component
        • Child component

Suppose the first child component was the subject of a conditional (on the master component). Every time the master component's data was updated, its conditionals would be reprocessed, meaning the child component would be re-rendered (and its script rerun), and so on for all that child component's children.

Did I help you? Feel free to be amazing and buy me a coffee on Ko-fi!