# Units

**Units** are the most important part of ActiveJS, they are responsible for holding the state of your single page application. Units can also be used independently, without any further knowledge of ActiveJS.

<div align="center"><img src="https://1597575908-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M6W6qxSNpirGD4JLBmY%2F-M8eiu5mJsGJqYjfw_F0%2F-M8f0JyjikwuyoDqgRVD%2FUnits%20Data%20Flow.svg?alt=media&#x26;token=2b497a3c-fad9-437b-9037-d326293eff53" alt="Two way data-flow between View Components and a shared Unit."></div>

Units are specialized, reactive data structures based on JavaScript's native data structures like `boolean`, `string` or `array`.&#x20;

For example, [ListUnit](https://docs.activejs.dev/activejs/fundamentals/units/listunit) is an elaborate `array` like data structure which is also an Observable and implements all the `Array.prototype` methods in a way that, any mutation caused by these methods, emits a new `array` with the mutations applied to it.

The actual value is stored inside the Unit and can be accessed via the `value()` method.

All the available Units are [BoolUnit](https://docs.activejs.dev/activejs/fundamentals/units/boolunit), [NumUnit](https://docs.activejs.dev/activejs/fundamentals/units/numunit), [StringUnit](https://docs.activejs.dev/activejs/fundamentals/units/stringunit), [ListUnit](https://docs.activejs.dev/activejs/fundamentals/units/listunit), [DictUnit](https://docs.activejs.dev/activejs/fundamentals/units/dictunit), and [GenericUnit](https://docs.activejs.dev/activejs/fundamentals/units/genericunit).

### ▶ Initializing a Unit

A Unit has several configuration options, including an optional initial-value.

```typescript
const unit1 = new NumUnit();
// OR
const unit2 = new NumUnit({initialValue: 0});
// OR
const unit3 = new NumUnit({initialValue: 5, cacheSize: 10});
```

Every type of Unit has a designated default value. `NumUnit` has `0` as the default value, and `StringUnit` has `''`. That's why in the above example the `unit1` and `unit2` are equivalent.

### 📑 Accessing the value

```typescript
// static access
console.log(unit1.value()); // logs 0

// reactive access
unit1.subscribe(value => console.log(value)) // logs 0, will log future values

// reactive non-replay access
unit1.future$.subscribe(value => console.log(value)) // will only log future values
```

As you might've noticed, when subscribing to the `unit1`, a value immediately gets logged to the console even though we haven't dispatched any value yet. If you are only interested in future values you can use `future$` Observable, which doesn't replay the last value on subscription, it only emits future values.

### 📡 Dispatching a value

All Units ignore any invalid value dispatch, Units only accept their designated value type, except the [GenericUnit](https://docs.activejs.dev/activejs/fundamentals/units/genericunit), because it's designed to accept and store all types of values.

```typescript
// initialize
const numUnit = new NumUnit(); // value is 0

// dispatch a new value
numUnit.dispatch(42); // returns true for successful dispatch
// value is 42 now

// using dispatch method with a value-producer function
numUnit.dispatch(currentValue => currentValue + 1);
// value is 43 now

// invalid dispatch
numUnit.dispatch('a string'); // this will be ignored, returns false
// value is still 43
```

There are two ways to dispatch a new value. You can pass a **value** or a **value-producer-function** to generate a new value to the `dispatch` method, the `dispatch` method returns `true` or `false` depending on the success of dispatch, which you can use to make any further decisions.

### 🔙 Using the Cached values

All Units cache 2 values by default, it allows us to go back and forth through these cached-values in such a way that it doesn't affect the cached-values, only the current-value changes. The caching mechanism works almost exactly like browser history.

The cache can be utilized in many ways, but probably the most common use case would be **undo** and **redo** capabilities. For undo feature we can use `goBack` method and for redo we can use `goForward` method respectively.

To dive into more details, see [Caching](https://docs.activejs.dev/activejs/guides/caching) to understand how it works.

```typescript
// create a Unit with default cache-size of 2
const unit = new StringUnit({initialValue: 'a'}); 

// cache is ['a']

unit.goBack(); // won't work, returns false
unit.goForward(); // won't work, returns false

unit.dispatch('b'); // cache becomes ['a', 'b']
console.log(unit.value()) // logs 'b'

unit.goBack(); // cache is still ['a', 'b']
console.log(unit.value()) // logs 'a'

unit.goForward(); // cache is still ['a', 'b']
console.log(unit.value()) // logs 'b'

// we can also access all the cached values
console.log(unit.cachedValues()) // logs ['a', 'b']

// or check the current cache index
console.log(unit.cacheIndex) // logs 1

// or check the count of cached values
console.log(unit.cachedValuesCount) // logs 2
```

### ↺ Clear & Reset

Resetting a Unit to it's initial-value is as easy as calling a method. Similarly clearing the value is also that easy.

```typescript
// create a Unit
const unit = new NumUnit({initialValue: 69});

// clear the value
unit.clearValue(); // now value is 0 (the default value for NumUnit)

// reset the value
unit.resetValue(); // now value is 69 again (the initial-value)
```

### 💎 Immutability

To demonstrate immutability we'd need a different kind of Unit because the [NumUnit](https://docs.activejs.dev/activejs/fundamentals/units/numunit) deals with a primitive type `number` which is already immutable.

Let's take a [ListUnit](https://docs.activejs.dev/fundamentals/units/listunit) to create a reactive, `array` like data structure.

```typescript
// initialize a immutable ListUnit.
const randomList = new ListUnit({immutable: true});
// ListUnit has default initial value []

// subscribe for the value
randomList.subscribe(value => console.log(value));
// logs [] immediately and will log future values
```

We just created an immutable Unit, that's all it takes, a configuration flag.

**✔ Mutation check**

```typescript
const anItem = {type: 'city', name: 'Delhi'};
randomList.push(anItem);
// this push is reactive, it'll make the Unit emit a new value

// let's try mutation by reference
anItem.type = 'state'; // this would work
// but the value of the randomList won't be affected, because every time
// a value is provided to an immutable list,
// it's cloned before storing.

// let's try another approach
const extractedValue = randomList.value(); // get the current value
console.log(listValue); // logs [{type: 'city', name: 'Delhi'}]
// try to mutate the extractedValue
extractedValue[1] = 'let me in...'; // this would work
// but the value of the randomList won't be affected, because every time
// an immutable list provides a value, it's cloned,
// to destroy all references to the stored value.
```

See [Immutability guide](https://docs.activejs.dev/activejs/guides/immutability) for more details.

### ⚓ Persistence

To make a Unit persistent, all we need is a unique id so that the Unit can identify itself in the `localStorage`, and a configuration flag.

```typescript
// initialize
const persitentUnit = new StringUnit({id: 'userName', persistent: true});
// StringUnit has default inital value ''
```

That's it, this StringUnit is persistent, it already saved its default value to `localStorage`.

**✔ Persistence check**

```typescript
// let's dispatch a new value different than the default value to 
// properly test the persistence
persitentUnit.dispatch('Neo');
console.log(persitentUnit.value()); // logs 'Neo'

// now if we re-initialize the same Unit
// on second initialization the Unit will restore its value from localStorage
// e.g: after a window refresh
console.log(persitentUnit.value()); // logs 'Neo'
```

See [Persistence guide](https://docs.activejs.dev/activejs/guides/persistence) for more details.

### 🔁 Replay and Replay-ness

Every Unit immediately provides the value when subscribed, by default, but maybe you only want the future values. For that purpose, every Unit has a built-in alternative Observable that doesn't emit immediately on subscription.

```typescript
const unit = NumUnit(); // NumUnit has default initialValue 0

// normal subscription
unit.subscribe(v => console.log(v)) // immediately logs 0

// future only subscription
unit.future$.subscribe(v => console.log(v)) // doesn't log anything

// both will log any future values
unit.dispatch(42); // you'll see two 42 logs in the console
```

You can also turn the default replay-ness off.

```typescript
const unit = NumUnit({replay: false});
// now default Observable and future$ Observable are the same

// normal subscription
unit.subscribe(v => console.log(v)) // doesn't log anything

// future only subscription
unit.future$.subscribe(v => console.log(v)) // doesn't log anything

// both will log any future values
unit.dispatch(42); // you'll see two 42 logs in the console
```

{% hint style="info" %}
By default, every Unit behaves like a [BehaviorSubject](https://www.learnrxjs.io/learn-rxjs/subjects/behaviorsubject), but unlike a BehaviorSubject Units don't require an explicit default value, since a Unit already has a default value.&#x20;
{% endhint %}

### 🔂 Manual Replay

Imagine a Unit is being used as a source for an API request, and you have a "refresh" button to trigger the request again. For this and many other scenarios, Units provide a manual `replay` method.

```typescript
const unit = StringUnit({initialValue: 'Alpha'});

unit.subscribe(v => /*make API request*/); // send every value to the server

unit.dispatch('Sierra'); // send another value

// to emit the same value again, all you have to do is
unit.replay();
// all subscribers will get the same value again, in this case, 'Sierra'
// so the server should receive 'Alpha', 'Sierra', 'Sierra'
```

### ❄ Freezing

If you want a Unit to stop accepting new values, in scenarios where the state is not supposed to change. All you need to do is this:

```typescript
// create a Unit
const unit = DictUnit(); // a DictUnit has default value {}

// freeze the Unit
unit.freeze();

// this will be ignored
unit.dispatch({'nein': 'nein nein'})
// so will any other mutative, or cache-navigation methods
// like goBack(), goForward(), clearValue(), resetValue() etc.

// unfreeze the Unit, and everything will start working again
unit.unfreeze();
```

See [Freezing guide](https://docs.activejs.dev/activejs/guides/freeze-and-mute) for more details.

### 🔇 Muting

If you want a Unit to stop emitting new values, but keep accepting new values, in scenarios where you aren't interested in new values but still don't want to lose them. All you need to do is mute the Unit.

```typescript
// create a Unit
const unit = GenericUnit(); // a GenericUnit has default value undefined
// it accepts all kinds of values as the name suggests

// mute the Unit
unit.mute();

// this will work
unit.subscribe(value => console.log(value));
// logs undefined immediately, but will not log any new values until unmuted

// this will still work
unit.dispatch('Hello'); // but no subscriber will get triggered

// but if you check the value, you'll get still get the updated value
console.log(unit.value()); // logs 'Hello'

// unmute the Unit, and if the value changed while the Unit was muted,
// emit it to all the subscribers, to bring them in sync
unit.unmute();
```

See [Muting guide](https://docs.activejs.dev/activejs/guides/freeze-and-mute) for more details.

### 📅 Events

Every Unit emits an event for every operation performed on it, you can tap into these events to take some other action.

```typescript
// create a Unit
const listUnit = new ListUnit();

// subscribe to events
listUnit.events$.subscribe(event => console.log(event));
```

There's an event for almost every operation that can be performed on a Unit, for example:

```typescript
// a succefull dispatch
listUnit.dispatch([69]); // will emit EventUnitDispatch
// an invalid dispatch
listUnit.dispatch({}); // will emit EventUnitDispatchFail
// on freeze
listUnit.freeze(); // will emit EventUnitFreeze
// on ListUnit specific methods
listUnit.push("Hard"); // will emit EventListUnitPush with value "Hard"
// another example
listUnit.pop(); // will emit EventListUnitPop
// and so on...
```

See [Events guide](https://docs.activejs.dev/activejs/guides/events) for more details.

### 🛠 Units vs native data structures

Units can not be used as drop-in replacements for native data structures. \
However, in most scenarios, a Unit instance can be used directly instead of `Unit.value()`

Every Unit implements [valueOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf) and [toString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString) methods. JavaScript automatically invokes these methods when encountering an object where a primitive or string value is expected, respectively. Hence [NumUnit](https://docs.activejs.dev/activejs/fundamentals/units/numunit), [StringUnit](https://docs.activejs.dev/activejs/fundamentals/units/stringunit), and [BoolUnit](https://docs.activejs.dev/activejs/fundamentals/units/boolunit) can be used similar to their primitive counterparts.

Additionally, Units also implement their counterparts prototype methods like [NumUnit](https://docs.activejs.dev/activejs/fundamentals/units/numunit) implements `Number.prototype` methods to make it easier to work with the stored value. Similarly, [ListUnit](https://docs.activejs.dev/activejs/fundamentals/units/listunit) implements all the `Array.prototype` methods, [StringUnit](https://docs.activejs.dev/activejs/fundamentals/units/stringunit) implements all the `String.prototype` methods, and so on.

#### **`number` vs** [**NumUnit**](https://docs.activejs.dev/activejs/fundamentals/units/numunit)

```typescript
const num = 42069;
const numUnit = new NumUnit({initialValue: 42069});

num.toString() // '42069'
numUnit.toString() // '42069'

num.toLocaleString() // '42,069' (in an 'en' locale)
numUnit.toLocaleString() // '42,069' (in an 'en' locale)

num + 1 // 42070
numUnit + 1 // 42070 // this doesn't change the Unit's value

num + 'XX' // '42069XX'
numUnit + 'XX' // '42069XX' // this doesn't change the Unit's value
```

**`array` vs** [**ListUnit**](https://docs.activejs.dev/activejs/fundamentals/units/listunit)

```typescript
const arr = ['👽', '👻'];
const listUnit = new ListUnit({initialValue: ['👽', '👻']});

arr.toString() // '👽,👻'
listUnit.toString() // '👽,👻'

arr.join('--') // '👽--👻'
listUnit.join('--') // '👽--👻'

arr.push('🤖') // mutates the same array
listUnit.push('🤖') // this is reactive, creates and dispatches a new array

// ListUnit is also iterable
[...arr] // a shallow copy of arr ['👽', '👻']
[...listUnit] // a shallow copy of stored value ['👽', '👻']

// and every Unit works with JSON.stringify
JSON.stringify({num, arr}) // '{"num":42069, "arr": ["👽", "👻"]}'
JSON.stringify({numUnit, listUnit}) // '{"numUnit":42069, "listUnit": ["👽", "👻"]}'
```

There are even more cases where you can treat a Unit just like a native data structure, barring a few exceptions like [ListUnit](https://docs.activejs.dev/activejs/fundamentals/units/listunit) and [DictUnit](https://docs.activejs.dev/activejs/fundamentals/units/dictunit) don't have key-based property access and assignment, they use `get` and `set` methods instead. And the fact that [BoolUnit](https://docs.activejs.dev/activejs/fundamentals/units/boolunit), [NumUnit](https://docs.activejs.dev/activejs/fundamentals/units/numunit) or [StringUnit](https://docs.activejs.dev/activejs/fundamentals/units/stringunit) aren't actually primitives, the `typeof` operator will only return `object`.

#### More Examples

```typescript
const numUnit = new NumUnit({initialValue: 3});
// current value is 3

numUnit + 1 // 4
// is same as this
numUnit.value() + 1 // 4

numUnit + 'idiots' // '3idiots'
// is same as this
numUnit.value() + 'idiots' // '3idiots'

JSON.stringify({n: numUnit}) // {n: 3}
// is same as this
JSON.stringify({n: numUnit.value()}) // {n: 3}


// that's pretty much it, 
// in other situations the Unit will behave like an object, as it should
numUnit === 3 // false
typeof numUnit === 'object' // true
numUnit++ // won't work, it will try to replace numUnit const with number 4

// similarly

const boolUnit = new BoolUnit({initialValue: false});

boolUnit + '' // 'false'
boolUnit + 1 // 1, because false is converted to 0
boolUnit.dispatch(true);
boolUnit + 1 // 2, because true is converted to 1

// similarly

const strUnit = new StringUnit({initialValue: 'Hello'});

strUnit + ' World' // 'Hello World'
strUnit + 1 // 'Hello1'
strUnit.dispatch('6');
parseInt(strUnit) // 6
```

### 📊 Units vs BehaviorSubject

|                                                                                     | Unit | BehaviorSubject |
| ----------------------------------------------------------------------------------- | ---- | --------------- |
| Replays value on subscription                                                       | ✅    | ✅               |
| Can be configured to not replay value on subscription                               | ✅    | ❌               |
| Allows to listen to only future values                                              | ✅    | ❌               |
| Accepts an initial-value                                                            | ✅    | ✅               |
| Can cache more than one value                                                       | ✅    | ❌               |
| Allows cache-navigation                                                             | ✅    | ❌               |
| Validates dispatched values                                                         | ✅    | ❌               |
| Specialized for specific data structures                                            | ✅    | ❌               |
| Can re-emit/replay last value manually                                              | ✅    | ❌               |
| Can be frozen                                                                       | ✅    | ❌               |
| Can be muted                                                                        | ✅    | ❌               |
| Can be immutable                                                                    | ✅    | ❌               |
| Can be persistent                                                                   | ✅    | ❌               |
| Can be reset                                                                        | ✅    | ❌               |
| Can be part of a [Cluster](https://docs.activejs.dev/activejs/fundamentals/cluster) | ✅    | ❌               |

## Configuration Options

The configuration options can be passed at the time of instantiation. All the configuration options are optional. You can set them per Unit or you can also set most of them globally. See [Configuration](https://docs.activejs.dev/activejs/guides/configuration) for more details.
