Patterns

Stores - Use as many stores as you'd like and however you'd likeAppComponents - Component-to-store proxiesComponents - JavaScript block statements in construct() to mimic markupComponents - Call update() at the end of construct() for populating elements with contentComponents - bind() & unbind()Stores - construct() & destroy()

Stores - Use as many stores as you'd like and however you'd like
  • Stores just mediate state
  • You can use multiple stores if you'd like (perhaps different stores for different responsibilities)
  • Stores can even contain internal stores (if you feel your store is growing too large)
  • Components can even contain internal stores (for complex components)
AppComponents - Component-to-store proxies
Stores play a very fundamental role in Duck, but they naturally make your components less reusable. Luckily, for components that need to be reusable, you can use the Duck AppComponent pattern!
The AppComponent pattern is to not use any stores in your Component files, but rather, rely on data only. Then, you can implement AppComponent files which proxy store state to a Component instance.
function AppComponent(data) {
  let component, elem;
  const store = data.store;

  function construct() {
    component = new Component(data);
    elem = component.elem;
    store.on('value', update);
  }

  function update() {
    component.data.text = store.getValue();
    component.update();
  }

  function enter() { component.enter(); }
  function exit() { component.exit(); }

  function destroy() {
    store.off('value', update);
    component.destroy();
  }

  construct();
  return { elem, data, update, enter, exit, destroy };
}
JavaScript
In essence, an AppComponent is functionally the same as Component but is "plugged in" to the store(s). The AppComponent code is certainly redundant looking, but the advantage of all of it is that the underlying Component is completely indepenent! The underlying Component can even be used in entirely different apps!
It is also worth noting that an AppComponent shares the same data object with its inner Component instance, which is against the Duck core principle that all Duck instances need their own data object. Gasp! But, in this case, it's actually okay because there is a one-to-one relation between the AppComponent and its inner Component instance.
Components - JavaScript block statements in construct() to mimic markup
Do,
function Component(data) {
  let elem;
  let childElem, grandchild1Elem, grandchild2Elem;
  // ...
  function construct() {
    elem = document.createElement('div');
    elem.className = 'root';
    {
      childElem = document.createElement('div');
      childElem.className = 'child';
      elem.appendChild(childElem);
      {
        grandchild1Elem = document.createElement('div');
        grandchild1Elem.className = 'grandchild-1';
        grandchild1Elem.innerHTML = '1';
        childElem.appendChild(grandchild1Elem);

        grandchild2Elem = document.createElement('div');
        grandchild2Elem.className = 'grandchild-2';
        grandchild2Elem.innerHTML = '2';
        childElem.appendChild(grandchild2Elem);
      }
    }
  }
  // ...
}
JavaScript
To mimic,
<div class="root">
  <div class="child">
    <div class="grandchild-1">1</div>
    <div class="grandchild-2">2</div>
  </div>
</div>
JavaScript
It's slightly longer, but it helps readability!
Components - Call update() at the end of construct() for populating elements with content
Do,
function Component(data) {
  function construct() {
    // ...
    update();
  }
}
JavaScript
The idea is that construct() is for structure and update() is for content.
Components - bind() & unbind()
The bind() and unbind() functions could easily have been part of Duck's core but were left out in order to keep core as small as possible. Essentially, bind() and unbind() are convenience functions for subscribing/unsubscribing to events.
Call bind() in construct() and unbind() in destroy().
function Component(data) {
  function construct() {
    // ...
    bind();
    update();
  }
  // ...
  function destroy() {
    unbind();
  }
  // ...
  ////////////////////////////////////////////////////////////////

  function bind() {
    store.on('eventA', update);
    store.on('eventB', update);
  }
  function unbind() {
    store.off('eventA', update);
    store.off('eventB', update);
  }

  ////////////////////////////////////////////////////////////////
}
JavaScript
As you can see, unbind() is a mirror opposite of bind() with off() calls instead of on() calls! It's actually very convenient to work with them right next to each other.
NOTE: Don't forget to actually put the bind() and unbind() calls inside construct() and destroy()!
Stores - construct() & destroy()
If you have a store that requires initialization (fetching data, subscribing to events, etc), simply add a construct() function that is essentially identical to a component construct() function. After all, Stores and Components are just Ducks!
function Store(data) {

  // ...

  function construct() {
    // initialization - fetch data, add listeners, etc
  }

  function destroy() {
    // remove listeners
  }

  // ...

  construct();
  return {
    // ...
    destroy,
    on, off
  };

  // ...
}
JavaScript
Naturally, a construct() function means you also need a destroy() function to prevent memory leaks, so be sure to include a callable destroy() function as well!
Oh, and if you're wondering, the bind() & unbind() recipe can be applied to stores as well!
It's also worth noting that you don't technically NEED a construct() function to perform initialization. You can always just do initialization(s) in the stores when declaring varibles. I just find construct() generally cleaner and easier to read.