Skip to content

Reactivator API: reactive()

Appurist (Paul) edited this page Sep 18, 2020 · 4 revisions

reactive()

Parameters: (object)

Returns: a reactive version (copy) of the specified object

This method wraps a JavaScript data object with a new object that provides reactivity. It is similar to the reactive() function in the Vue 3 Composition API.

IMPORTANT: The returned value is a copy of the data, not the original data itself. All data access should be performed though the object returned, otherwise reactive observations may not generate for changes to the members.

Example usage:

import { reactive, watch, unwatch, dumpValue } from 'reactivator'

let state = reactive({field1: 42, field2: 'hello'})

function onStateChange(old, val, prop, name, obj) {
  let context = name ? 'state'+name : 'state'
  console.log(`${context}.${[prop]} has changed from ${dumpValue(old)} to ${dumpValue(val)}`)
}

state.field1 = 99;  // no watch installed yet

// Let's define a more complex watch handler for object and array changes
watch(state, onStateChange)

state.field1 = 100;
state.field3 = 'completely new';
state.field2 = 'Goodbye';

state.emptyArray = [  ];

state.newArray = [ 'one', 'two' ];
state.newArray.push('three');

state.sub1 = { sub1a: 'value1a', sub1b: 'value1b' };
state.sub1.sub1b = 'new1b';

unwatch(state, onStateChange); // now uninstall the watch
state.field1 = 101;

Resulting output:

state.field1 has changed from 99 to 100
state.field3 has changed from undefined to 'completely new'
state.field2 has changed from 'hello' to 'Goodbye'
state.emptyArray has changed from undefined to [ ]
state.newArray has changed from undefined to ['one','two']
state.newArray.2 has changed from undefined to 'three'
state.newArray.length has changed from 3 to 3
state.sub1 has changed from undefined to [object Object]
state.sub1.sub1b has changed from 'value1b' to 'new1b'

Example 2: Improved watch function

This example provides more accurate reporting of the changes, through the use of a more complex onStateChange watch handler function. Also, when it detects the change is an object, it passes a true to dumpValue in order to have the value dumped as JSON:

import { reactive, watch, unwatch, dumpValue } from 'reactivator'

let state = reactive({field1: 42, field2: 'hello'})

// Let's define a more complex watch handler for object and array changes
function onStateChange(old, val, prop, name, obj) {
  let label = name ? `test3${name}` : 'test3';
  if (Array.isArray(obj) && prop === 'length')
    console.log(`watch: ${label}.${prop} changed to ${dumpValue(val)}`);
  else
  if (Array.isArray(obj) && parseInt(prop))
    console.log(`watch: ${label}[${prop}] changed from ${dumpValue(old)} to ${dumpValue(val)}: ${dumpValue(obj)}`);
  else
  if (old !== undefined) 
    console.log(`watch: ${label}.${prop} changed from ${dumpValue(old)} to ${dumpValue(val)}`);
  else
  if (Array.isArray(val))
    console.log(`watch: ${label}.${prop} assigned a new array ${dumpValue(val)}`);
  else
  if (typeof val === 'object')
    console.log(`watch: ${label}.${prop} assigned a new object: ${dumpValue(val, true)}`);
  else
    console.log(`watch: ${label}.${prop} assigned value ${dumpValue(val)}`);
}

state.field1 = 99;  // no watch installed yet

// Let's define a more complex watch handler for object and array changes
watch(state, onStateChange)

state.field1 = 100;
state.field3 = 'completely new';
state.field2 = 'Goodbye';

state.emptyArray = [  ];

state.newArray = [ 'one', 'two' ];
state.newArray.push('three');

state.sub1 = { sub1a: 'value1a', sub1b: 'value1b' };
state.sub1.sub1b = 'new1b';

unwatch(state, onStateChange); // now uninstall the watch
state.field1 = 101;

Resulting output:

watch: test3.field1 changed from 99 to 100
watch: test3.field3 assigned value 'completely new'
watch: test3.field2 changed from 'hello' to 'Goodbye'
watch: test3.emptyArray assigned a new array [ ]
watch: test3.newArray assigned a new array ['one','two']
watch: test3.newArray.2 assigned value 'three'
watch: test3.newArray.length changed from 3 to 3
watch: test3.sub1 assigned a new object: {"sub1a":"value1a","sub1b":"value1b"}
watch: test3.sub1.sub1b changed from 'value1b' to 'new1b'