# Fundamentals

ActiveJS has 4 fundamental types of constructs, [Units](https://docs.activejs.dev/activejs/fundamentals/units), [Systems](https://docs.activejs.dev/activejs/fundamentals/systems), [Action](https://docs.activejs.dev/activejs/fundamentals/action), and [Cluster](https://docs.activejs.dev/activejs/fundamentals/cluster). All these constructs are Observables since they extend RxJS' Observable class.

You don't need to learn all of them to start using ActiveJS; [Units](https://docs.activejs.dev/activejs/fundamentals/units) and [Actions](https://docs.activejs.dev/activejs/fundamentals/action) can be used independently without any further understanding of [Systems](https://docs.activejs.dev/activejs/fundamentals/systems) or [Clusters](https://docs.activejs.dev/activejs/fundamentals/cluster). 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.

![](https://1597575908-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M6W6qxSNpirGD4JLBmY%2F-MAsFH3yDU9S0O2wrt5E%2F-MAus4bPOAPnL1weZwja%2FHigh%20Level%20Data%20Flow%20\(1\).svg?alt=media\&token=e7494c6e-0ec8-434f-8746-1699109aec09)

### 1. [Units](https://docs.activejs.dev/activejs/fundamentals/units)

* 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`.
  * [**BoolUnit**](https://docs.activejs.dev/activejs/fundamentals/units/boolunit) is a `boolean` counterpart, it stores and provides a `boolean` value at all times.
  * [**NumUnit**](https://docs.activejs.dev/activejs/fundamentals/units/numunit) is a `number` counterpart, it stores and provides a `number` value at all times.
  * [**StringUnit**](https://docs.activejs.dev/activejs/fundamentals/units/stringunit) is a `string` counterpart, it stores and provides a `string` value at all times.
  * [**ListUnit**](https://docs.activejs.dev/activejs/fundamentals/units/listunit) is an `array` counterpart, it stores and provides an `array` value at all times.
  * [**DictUnit**](https://docs.activejs.dev/activejs/fundamentals/units/dictunit) is loosely based on `Map`, it stores and provides a simple `object` value at all times.
  * [**GenericUnit**](https://docs.activejs.dev/activejs/fundamentals/units/genericunit) doesn't pertain to any specific data type, it's generic in nature, it can store any type of value.

```typescript
// 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'
```

### **2.** [**Systems**](https://docs.activejs.dev/activejs/fundamentals/systems)

* Reactive storage Systems help with async APIs like **XHR** and **fetch** or any third party abstraction.
* A System is just a systematic combination of one or more [Units](https://docs.activejs.dev/activejs/fundamentals/units) with pre-configured inter-relationships.
* For example, [AsyncSystem](https://docs.activejs.dev/activejs/fundamentals/systems/asyncsystem) 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** [GenericUnits](https://docs.activejs.dev/activejs/intro/getting-started), one each for `query`, `response` and `error`, and **one** [BoolUnit](https://docs.activejs.dev/activejs/fundamentals/units/boolunit) for the `pending-status` of an async task.

```typescript
// 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.

```typescript
// 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:

```typescript
// 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});
```

### **3.** [**Actions**](https://docs.activejs.dev/activejs/fundamentals/action)

* Actions are meant to represent unique reactive events. Action is an RxJS [Subject](https://rxjs.dev/guide/subject) like construct, it also extends RxJS Observable, and implements custom features like replay on demand.
* Actions help trigger customized operations in a reactive fashion.

```typescript
// 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'
```

### **4.** [Clusters](https://docs.activejs.dev/activejs/fundamentals/cluster)

* A Cluster is a wrapper of two or more [Units](https://docs.activejs.dev/activejs/fundamentals/units), [Systems](https://docs.activejs.dev/activejs/fundamentals/systems), [Actions](https://docs.activejs.dev/activejs/fundamentals/action), or even [Clusters](https://docs.activejs.dev/activejs/fundamentals/cluster). It's intended to be used to create a group of several ActiveJS instances.
* 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.

```typescript
// 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
```
