LogoLogo
  • Introduction
  • Intro
    • 🚀Getting Started
    • Key Characteristics
    • Fundamentals
    • Motivation
  • Fundamentals
    • 💾Units
      • BoolUnit
      • NumUnit
      • StringUnit
      • DictUnit
      • ListUnit
      • GenericUnit
    • 🤝Systems
      • AsyncSystem
      • Custom AsyncSystem
    • 🤜Action
    • 📦Cluster
  • 🔨Utilities
    • Stream
    • Selection
  • Integrations
    • Angular
    • React
      • useObservable Hook
      • useUnit Hook
  • 📖Guides
    • Configuration
    • Nesting
    • Events
    • Typings
    • Caching
    • Persistence
    • Immutability
    • Freeze and Mute
    • Development Environment
    • General Guidelines
  • More
    • 👀Examples
    • ✍️Articles
Powered by GitBook
On this page
  • 1. Units
  • 2. Systems
  • 3. Actions
  • 4. Clusters

Was this helpful?

  1. Intro

Fundamentals

PreviousKey CharacteristicsNextMotivation

Last updated 4 years ago

Was this helpful?

ActiveJS has 4 fundamental types of constructs, , , , and . All these constructs are Observables since they extend RxJS' Observable class.

You don't need to learn all of them to start using ActiveJS; and can be used independently without any further understanding of or . Also, ActiveJS is tree-shakeable, hence the parts that you don't use, will not get bundled in your build.

This data-flow diagram might give you some perspective before we dive into details. It shows how ActiveJS is connected with other parts of a Web app. All parts of an App can communicate with any instance of an ActiveJS construct directly, there is no abstraction layer involved like a Store, Dispatcher, Middleware, or Reducer.

  • Every state management solution relies on a robust storage system, and for that exact purpose, ActiveJS has independent, reactive storage Units. Simply called Units.

  • Units emulate JavaScript's native data structures. There's a specialized type of Unit for each of the most used native data structures. All the Units are also Observables.

// initialize a Unit
const messageUnit = new StringUnit(); // StringUnit has default-value ''

// listen for the values
messageUnit.subscribe(value => console.log(value));
// logs '' immediately, and will log 'hello' after next step

// dispatch a new value
messageUnit.dispatch('hello'); // StringUnit only acccepts strings

// directly access value
console.log(messageUnit.value()); // logs 'hello'
  • Reactive storage Systems help with async APIs like XHR and fetch or any third party abstraction.

// initialize a System for fetching and sharing user data
const userDataSystem = new AsyncSystem();

// extract the Units, that are part of the AsyncSystem
const {queryUnit, dataUnit, errorUnit, pendingUnit} = userDataSystem;
// using destructuring assignment

// a function to fetch data and disptch the response appropriately
async function fetchAndShareData(query) {
  try {
    // fetch data using fetch API
    const response = await fetch('https://xyz.com/u/' + query.userId);
    // extract the JSON data
    const data = await response.json();

    // dispatch data to the dataUnit, it also sets the pendingUnit's value to false
    // and it also clears the errorUnit's value
    dataUnit.dispatch(data);
  } catch (err) {
    // dispatch error to errorUnit, it also sets the pendingUnit's value to false
    errorUnit.dispatch(err);
  }
}

// setup the stream by observing query values, that triggers fetchAndShareData
// whenever a value is dispatched to queryUnit
queryUnit.subscribe(query => fetchAndShareData(query));

Our setup is complete, now we can easily share query, data, error and pending-status with different parts of our App.

// listen for queries
queryUnit.subscribe(query => console.log(query));

// listen for data
dataUnit.subscribe(data => console.log(data));

// listen for errors
errorUnit.subscribe(error => console.log(error));

// listen for pending status
pendingUnit.subscribe(isPending => console.log(isPending));

Now, all we need to do is trigger a new API request, which also can be done from anywhere, like this:

// dispatch a query, it'll also set pendingUnit's value to true
// the rest will be handled by the stream we just created above
queryUnit.dispatch({userId: 42069});
  • Actions help trigger customized operations in a reactive fashion.

// initialize an Action
const notifier = new Action();

// every time the Action emits, we alert
notifier.subscribe(message => alert(message));
// not executed on subscription, waits for a dispatch

// we can dispatch any value from anywhere
notifier.dispatch('Say Sike');

// replay the last value
notifier.replay(); // will emit 'Say Sike' again

// directly access value
console.log(notifier.value()); // logs 'Say Sike'
  • It creates a master Observable of combined values of provided members of the Cluster.

  • It also provides direct access to its members and their combined value.

// create a few Units to combine
const numUnit = new NumUnit(); // with default value 0
const strUnit = new StringUnit(); // with default value ''
const listUnit = new ListUnit(); // with default value []

// create a Cluster
const myPrecious = new Cluster({numUnit, strUnit, listUnit})
// using shorthand notation

// static value access
console.log(myPrecious.value())

// and reactive value access, emits whenever a memeber emits
myPrecious.subscribe(value => console.log(value));

// both will immediately log the following
{
  numUnit: 0, strUnit: '', listUnit: []
}

// accessing the Unit through the Cluster
console.log(myPrecious.items.numUnit.value()); // logs 0

1.

is a boolean counterpart, it stores and provides a boolean value at all times.

is a number counterpart, it stores and provides a number value at all times.

is a string counterpart, it stores and provides a string value at all times.

is an array counterpart, it stores and provides an array value at all times.

is loosely based on Map, it stores and provides a simple object value at all times.

doesn't pertain to any specific data type, it's generic in nature, it can store any type of value.

2.

A System is just a systematic combination of one or more with pre-configured inter-relationships.

For example, can be used to store, share, replay, and wait for async tasks. This is realized by utilizing four Units for every aspect of an async task, it includes three , one each for query, response and error, and one for the pending-status of an async task.

3.

Actions are meant to represent unique reactive events. Action is an RxJS like construct, it also extends RxJS Observable, and implements custom features like replay on demand.

4.

A Cluster is a wrapper of two or more , , , or even . It's intended to be used to create a group of several ActiveJS instances.

Units
BoolUnit
NumUnit
StringUnit
ListUnit
DictUnit
GenericUnit
Systems
Units
AsyncSystem
GenericUnits
BoolUnit
Actions
Subject
Clusters
Units
Systems
Actions
Clusters
Units
Systems
Action
Cluster
Units
Actions
Systems
Clusters