Skip to content
Batiste Bieler edited this page Mar 31, 2023 · 19 revisions

Blop offers a convenient and small library to handle state management changes based on the Proxy API. This library is not embedded in the language run time: it is as external import. You can chose to use it or any other state management you might find more appropriate.

A basic setup for the browser build might look like this:

// client.blop
import { mount } from 'blop'
import { createState } from './state.blop'
import { Index } from './index.blop'


// this create the state Proxy with some default data
proxiedState = createState({ dogs: [], fetchURL: "https://api.com/dogs" })

// The render function for this application
render = () => {
  proxiedState.$.flush() // full re-render: we can flush all recorded state changes
  tree = Index(proxiedState) // Call our Index component, giving it the state as parameter
  console.log('Client renderer executed')
  return tree // return the virtual DOM
}

// Boot up the app on the client, mount want a target DOM element and a render function.
// Return a refresh function and an initialisation function
{ refresh, init } = mount(document.getElementById('app'), render)

// this will call your render function, and fill up the target
// DOM element with the result (any DOM existing inside the target will be lost)
init()

// listen to any state change, and call refresh when any change happens
proxiedState.$.listen((path) => {
  refresh((time) => {
    if time > 50 => console.log(`Slow rendering time `time`ms triggered by `path``)
  })
})

Then the state can be used like any other parameter in your components:

// index.blop
Index = (state) => {
  async def fetchData(e) {
    // you can read any data from the state without side effect
    response = await fetch(state.fetchURL)
    // when state is changed, a full re-render of the application is scheduled
    state.dogs = response.dogs
  }
  state.anything = 1 // DONT: This will create an infinite rendering loop
  <div>
    <button class="btn" on={ click: fetchData }>'Fetch data'</button>
    for dogs in state.dogs {
      <p>dog.breed</p>
    }
  </div>
}

It should be clear at this point why changing the state within the rendering path of the component will schedule a new rendering. This is because proxiedState.$.listen will be called and this will create an infinite loop.

This kind of mistake can be easily detected and the loop automatically stopped. This is what is done in the complete example containing an infinite loop avoidance mechanism that you probably want to setup to detect and fix those errors easily.

Clone this wiki locally