Skip to content

Latest commit

 

History

History
177 lines (136 loc) · 5.36 KB

examples.md

File metadata and controls

177 lines (136 loc) · 5.36 KB

Examples

All examples are fully implemented in the examples/ directory.

Counter

In our counter example we define a simple DOM tree in the body of our document as such:

<section id="counter"> Counter: ${ total } </section>

The innerHTML of the DOM element #counter represent the source template of our container. A single identifier total is referenced.

A container for this DOM element can be created with createContainer(). We will provide an initial state object where with the value of { total: 0 }.

import { createContainer } from 'stardux'
const domElement = document.querySelector('#counter')
const container = createContainer(domElement, { total: 0 })

The createContainer() claims the given DOM element and updates its innerHTML providing initial state.

The DOM of the container should match the following:

<section id="counter"> Counter: 0 </section>

When updates occur to a container's DOM element tree, child nodes are diffed and patched when required. This is made possible with starplate templating and patching. At the core, diffs and patches are implemented with IncrementalDOM and based upon a DOM tree provided by starplate.

The .update() method on a Container instance updates the container state. In this example our concernis the value of total. We can update the value of total by passing an object to the .update() method.

container.update({total: 1})

The DOM of the container should match the following:

<section id="counter"> Counter: 1 </section>

We can retrieve the value of total by inspecting the .state object of a container.

const total = container.state.total

The state object returned when accessing the .state property is a copy of the internal state represented in the container. You can modify the object, but it will not affect the state of the container.

We now know the state of the container externally. We can now create two functions for incrementing and decrementing the total value.

function increment () {
  const total = container.state.total
  container.update({total: total + 1})
}

function decrement () {
  const total = container.state.total
  container.update({total: total - 1})
}

Calling either of these functions updates the state of the container. We can now increment or decrement the value of the counter by updating its internal container state.

Suppose we want to ensure that our counter has a minimum value. We want to impose that all values are greater than or equal to 0. We can achieve this with middleware. Middleware is a function that can manipulate state and action objects. It is executed before user reducers and will therefore affect the values on the state and action objects. Reducers and middleware are called for any type of action dispatched on a container. Our concern is only updates. When an action is dispatched on a container the .type value is defined on the action object. The UPDATE type is the action type dispatched when .update() is called. When an object is given to the update() method it is defined on the action object as the .data property.

We now need to import UPDATE type from the stardux module. Our import statement needs to change to the following:

import {
  UPDATE,
  createContainer
} from 'stardux'

Our middleware for imposing a minimum counter value could be defined as such:

function minimum (value) {
  const max = Math.max
  return (state, action) => {
    const total = action.data.total
    if (UPDATE == action.type) {
      action.data.total = max(value, max(value, total))
    }
  }
}

Middleware is mostly concerned with modifying the action object. Again, data given to the .update() method is set on the action object as the .data property.

Middleware is consumed with the .use() method on a container. We can install the minimum() middleware with a minimum value set to 0.

container.use(minimum(0))

All calls to decrement() should decrement the total but never let the value be less than 0.

Our counter, now with middleware and an API (increment(), decrement()) is ready for interaction. We can modify our document by adding two buttons that, when clicked, increment or decrement the counter.

<button type="button" onclick="increment()"> ( + ) Increment </button>
<button type="button" onclick="decrement()"> ( - ) Decrement </button>

Our counter now has a UI interaction allowing the container to be updated.

See examples/counter for the complete working example.