Version 2
What is new? Migration Guide From V1
Getting Started
Understanding WinnetouJs Setting Up
Constructos
Creating Constructos Advanced Options Lazy Loading
Mutables
Constructos State Management Case: Custom State Management System Winnetou FX
Addons
Winnetou Selectors Winnetou Router App Translations CSS Sass Built-in Transpiler SVG Icons Color Themes
Extras
Useful JsDoc Syntax
Plugins
Creating Plugins SlideScreen Official Plugin Animate Official Plugin
Compiling to Production
WBR
API Change Log Git Hub Pull Requests Guidelines Get in touch
Mutables

Custom State Management System

Mutables are not developed to use with lints, to solve this problem we create an approach that solves this.

Purpose

Mutables will always impact DOM because setMutable tries to locate constructos that need to refresh. To avoid this mechanism, create your own state management system that can split resources between store simple data and update shadow DOM.

Code

In below code we define an ephemeral memory that will store our data and we create get and set methods to access this data. To store persistent data we will use localstorage.

stateManagementMainClass.js

export class __StateManagement__ {
  constructor() {
    /**@private */
    this.ephemeralMemory = [];
  }

  /**
   * Print on console a report about state management actual stored data
   * @param {boolean} ephemeral true: show ephemeral data, false: show localstorage data
   */
  PRINT_STATE(ephemeral) {
    const printEphemeral = () => {
      console.warn("EPHEMERAL STATE MANAGEMENT DATA REPORT");
      console.log(this.ephemeralMemory);
    };

    const printLocalStorage = () => {
      let total = localStorage.length;
      let res = [];
      for (let c = 0; c < total; c++) {
        let key = localStorage.key(c);
        if (key.includes("sm_")) {
          res.push({
            key,
            value: localStorage.getItem(key),
          });
        }
      }
      //
      console.warn("LOCALSTORAGE STATE MANAGEMENT REPORT");
      console.table(res);
    };

    ephemeral ? printEphemeral() : printLocalStorage();
  }

  /**@private */
  del(key) {
    localStorage.removeItem("sm_" + key);
  }

  /**@private */
  set(key, value) {
    localStorage.setItem("sm_" + key, value);
  }
  /**
   *
   * @param {string} key
   * @param {string|Number|event|Array|Boolean} value
   */
  set_ephemeral(key, value) {
    this.ephemeralMemory[key] = value;
  }
  /**@private */
  get(key) {
    return localStorage.getItem("sm_" + key);
  }
  /**@private */
  get_ephemeral(key) {
    return this.ephemeralMemory[key];
  }
}


  

This JavaScript class, __StateManagement__, is a simple state management system that offers two storage options: ephemeral (temporary) and persistent (localStorage). Let’s go through the code to see how each part works.

Class: __StateManagement__

The class has two main storage mechanisms:

Constructor

constructor() {
  /**@private */
  this.ephemeralMemory = [];
}

This sets up an empty array ephemeralMemory to store temporary data. The @private comment indicates that it’s for internal use only.

Method: PRINT_STATE

PRINT_STATE(ephemeral)

Purpose: Logs a report to the console, showing either the ephemeral data or the data in localStorage, depending on the ephemeral parameter.

Parameter: ephemeral (boolean) - If true, it prints ephemeral data. If false, it logs localStorage data.

Helper Functions within PRINT_STATE

Method: del

del(key)

Purpose: Deletes an item from localStorage based on the given key.

Parameter: key (string) - The identifier for the item to delete.

Method: set

set(key, value)

Purpose: Stores an item in localStorage.

Parameters:

Method: set_ephemeral

set_ephemeral(key, value)

Purpose: Adds or updates an item in ephemeralMemory.

Parameters:

Method: get

get(key)

Purpose: Retrieves an item from localStorage using the given key.

Parameter: key (string) - The identifier for the item.

Method: get_ephemeral

get_ephemeral(key)

Purpose: Retrieves an item from ephemeralMemory using the specified key.

Parameter: key (string) - The identifier for the item.

This class provides a structured way to manage both temporary and persistent state data, making state retrieval and debugging easy with the PRINT_STATE method.

Now we can create our own class that extends those methods. In MyManager, we can create any methods we need to control out application.

stateManagementChild.js

import {Winnetou} from 'winnetoujs';
import {__StateManagement__} from './stateManagementMainClass';
class MyManager extends __StateManagement__{
  constructor(){
    super()
  }
  // put here your implementations

  device = {
    set:
      /**
       *
       * @param {"android"|"pc"|"mobile"} value
       * @returns
       */
      value => this.set_ephemeral("device", value),

    get:
      /**
       *
       * @returns {"android"|"pc"|"mobile"}
       */
      () => this.get_ephemeral("device"),

    isAndroid: () => this.get_ephemeral("device") === "android",

    isMobile: () => this.get_ephemeral("device") === "mobile",

    isPc: () => this.get_ephemeral("device") === "pc",
  };
}




This code defines a class, MyManager, which extends __StateManagement__ and provides additional functionality for managing device types within a state management system. Let’s break down each part of the code.

Imports

import { Winnetou } from 'winnetoujs';
import { __StateManagement__ } from './stateManagementMainClass';

This imports two modules:

Class: MyManager

class MyManager extends __StateManagement__ {
  constructor() {
    super();
  }
}

This class extends __StateManagement__, inheriting its state management methods (such as set_ephemeral and get_ephemeral). The constructor calls super() to ensure the base class is initialized.

Property: device

The device property in MyManager defines a set of methods for managing a "device" type within the ephemeral state. The possible values are "android", "pc", or "mobile". Let’s go over each method.

device.set

set:
  /**
   *
   * @param {"android"|"pc"|"mobile"} value
   * @returns
   */
  value => this.set_ephemeral("device", value),

Purpose: Sets the device type in the ephemeral memory.

Parameter: value - Can be "android", "pc", or "mobile".

This method calls this.set_ephemeral("device", value) to store the device type temporarily.

device.get

get:
  /**
   *
   * @returns {"android"|"pc"|"mobile"}
   */
  () => this.get_ephemeral("device"),

Purpose: Retrieves the current device type from ephemeral memory.

Returns: The stored device type, which can be "android", "pc", or "mobile".

device.isAndroid

isAndroid: () => this.get_ephemeral("device") === "android",

Purpose: Checks if the stored device type is "android".

Returns: true if the device type is "android", otherwise false.

device.isMobile

isMobile: () => this.get_ephemeral("device") === "mobile",

Purpose: Checks if the stored device type is "mobile".

Returns: true if the device type is "mobile", otherwise false.

device.isPc

isPc: () => this.get_ephemeral("device") === "pc",

Purpose: Checks if the stored device type is "pc".

Returns: true if the device type is "pc", otherwise false.

The MyManager class extends __StateManagement__ to manage device-specific states in ephemeral memory. The device property allows setting, getting, and checking device types, making it a simple and structured way to manage device information within the state management system.

Updating Constructos Using Mutables

mutables.js

// somewhere in code ...

MyManager.profile.stars.create()

profileCard({
  name:'John',
  stars: {mutable:'stars'} 
})

MyManager.profile.stars.add()
// it updates profileCard constructo automatically

// inside MyManager class
// ...

profile = {
  stars = {
    create: () => !Winnetou.getMutable('stars') && 
      Winnetou.setMutable('stars','0'),
    add: () => {
      let actualStars = parseInt(Winnetou.getMutable('stars')) || 0;
      actualStars++;
      Winnetou.setMutable('stars',actualStars);
    },
    remove: () => {
      let actualStars = parseInt(Winnetou.getMutable('stars')) || 0;
      actualStars--;
      actualStars < 0 && (actualStars = 0);
      Winnetou.setMutable('stars',actualStars);
    }
  }
}


This code expands the MyManager class to manage a "stars" property within a user profile. The "stars" value can be created, added to, or removed, and it interacts with an external UI component in real-time. Here’s how it works.

Code Usage Example

// somewhere in code ...

MyManager.profile.stars.create();

profileCard({
  name: 'John',
  stars: { mutable: 'stars' } 
});

MyManager.profile.stars.add(); 
// it updates profileCard construct automatically

This example shows how MyManager.profile.stars methods are used to create and update a "stars" counter associated with a profile. When the add() method is called, it automatically updates the profileCard UI to reflect the new stars count.

Property: profile in MyManager

The profile property defines a nested stars object, which contains methods to manage a user's "stars" count. The "stars" value is stored as a mutable state, accessible via the Winnetou library.

stars.create

create: () => !Winnetou.getMutable('stars') && 
  Winnetou.setMutable('stars', '0')

Purpose: Initializes the stars count if it doesn't exist yet. Checks if the "stars" mutable value exists; if not, it sets it to '0'.

stars.add

add: () => {
  let actualStars = parseInt(Winnetou.getMutable('stars')) || 0;
  actualStars++;
  Winnetou.setMutable('stars', actualStars);
}

Purpose: Increments the "stars" count by 1.

How it works: Retrieves the current "stars" value, parses it as an integer, increments by 1, and updates it in the mutable state. This change is reflected in any UI bound to stars, such as profileCard.

stars.remove

remove: () => {
  let actualStars = parseInt(Winnetou.getMutable('stars')) || 0;
  actualStars--;
  actualStars < 0 && (actualStars = 0);
  Winnetou.setMutable('stars', actualStars);
}

Purpose: Decrements the "stars" count by 1, but prevents it from going below zero.

How it works: Gets the current "stars" count, decreases it by 1, and ensures it doesn’t drop below 0. Updates the mutable state, automatically reflecting the change in any UI element bound to "stars."

This code provides a mechanism to manage a user's "stars" count within the MyManager class. The stars property inside profile allows for creating, incrementing, and decrementing the stars value. Using Winnetou to manage mutable state enables real-time updates, making it easy to sync the "stars" count with UI elements like profileCard.