All Projects → elbywan → Hyperactiv

elbywan / Hyperactiv

Licence: mit
A super tiny reactive library. ⚡️

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to Hyperactiv

Lychee
The most complete and powerful data-binding library and persistence infra for Kotlin 1.3, Android & Splitties Views DSL, JavaFX & TornadoFX, JSON, JDBC & SQLite, SharedPreferences.
Stars: ✭ 102 (-50.96%)
Mutual labels:  properties, reactive
Xian
reactive风格的微服务框架
Stars: ✭ 196 (-5.77%)
Mutual labels:  reactive
Rxgrdb
Reactive extensions for SQLite
Stars: ✭ 176 (-15.38%)
Mutual labels:  reactive
Siesta
The civilized way to write REST API clients for iOS / macOS
Stars: ✭ 2,142 (+929.81%)
Mutual labels:  reactive
Aesthetic
[DEPRECATED]
Stars: ✭ 2,044 (+882.69%)
Mutual labels:  reactive
Loca
Open source real estate management
Stars: ✭ 189 (-9.13%)
Mutual labels:  properties
Rxiglistkit
IGListKit with RxSwift🚀
Stars: ✭ 174 (-16.35%)
Mutual labels:  reactive
Pos
Sample Application DDD, Reactive Microservices, CQRS Event Sourcing Powered by DERMAYON LIBRARY
Stars: ✭ 207 (-0.48%)
Mutual labels:  reactive
Liiklus
Reactive (RSocket/gRPC) Gateway for the event-based systems
Stars: ✭ 192 (-7.69%)
Mutual labels:  reactive
Rxjava Spring Boot Starter
RxJava Spring MVC integration
Stars: ✭ 180 (-13.46%)
Mutual labels:  reactive
Reactorkit
A library for reactive and unidirectional Swift applications
Stars: ✭ 2,237 (+975.48%)
Mutual labels:  reactive
Redux Callbag
🕺🕺Redux middleware for action side effects with callbag 👉< 1KB
Stars: ✭ 177 (-14.9%)
Mutual labels:  reactive
Spring Webflux Security Jwt
A JWT authorization and authentication implementation with Spring Reactive Webflux, Spring Boot 2 and Spring Security 5
Stars: ✭ 190 (-8.65%)
Mutual labels:  reactive
Vs Shell Format
the shellscript、Dockerfile、properties ...... format extension
Stars: ✭ 176 (-15.38%)
Mutual labels:  properties
Barrel Platform
Distributed database for the modern world
Stars: ✭ 201 (-3.37%)
Mutual labels:  reactive
Reactor Addons
Official modules for the Reactor project
Stars: ✭ 175 (-15.87%)
Mutual labels:  reactive
Proteus
Lean, mean, and incredibly fast JVM framework for web and microservice development.
Stars: ✭ 178 (-14.42%)
Mutual labels:  reactive
Javawebsocketclient
RxJava WebSocket library for Java and Android
Stars: ✭ 188 (-9.62%)
Mutual labels:  reactive
Recaptcha
[In]visible ReCaptcha v2 for iOS
Stars: ✭ 208 (+0%)
Mutual labels:  reactive
Store
A beautifully-simple framework-agnostic modern state management library.
Stars: ✭ 204 (-1.92%)
Mutual labels:  reactive

Hyperactiv logo
Hyperactiv
npm-badge travis-badge Coverage Status license-badge

A super tiny reactive library. ⚡️

Description

Hyperactiv is a super small (~ 1kb minzipped) library which observes object mutations and computes functions depending on those changes.

In other terms whenever a property from an observed object is mutated, every function that depend on this property are called right away.

Of course, Hyperactiv automatically handles these dependencies so you never have to explicitly declare anything. ✨


Minimal working example

import hyperactiv from 'hyperactiv'
const { observe, compute } = hyperactiv

// This object is observed.
const observed = observe({
    a: 1,
    b: 2,
    c: 0
})

// Calling computed(...) runs the function and memorize its dependencies.
// Here, the function depends on properties 'a' and 'b'.
computed(() => {
    const { a, b } = observed
    console.log(`a + b = ${a + b}`)
})
// Prints: a + b = 3

// Whenever properties 'a' or 'b' are mutated…
observed.a = 2
// The function will automagically be called.
// Prints: a + b = 4

observed.b = 3
// Prints: a + b = 5

observed.c = 1
// Nothing depends on 'c', so nothing will happen.

Demo

Paint demo

React store demo

React hooks demo

Setup

npm i hyperactiv
<script src="https://unpkg.com/hyperactiv"></script>

Import

Hyperactiv is bundled as an UMD package.

// ESModules
import hyperactiv from 'hyperactiv'
// Commonjs
const hyperactiv = require('hyperactiv')
// Global variable
const { computed, observe, dispose } = hyperactiv

Usage

1. Observe object and arrays

const object = observe({ one: 1, two: 2 })
const array = observe([ 3, 4, 5 ])

2. Define computed functions

let sum = 0

// This function calculates the sum of all elements,
// which is 1 + 2 + 3 + 4 + 5 = 15 at this point.
const calculateSum = computed(() => {
    sum = [
        ...Object.values(object),
        ...array
    ].reduce((acc, curr) => acc + curr)
})

// A computed function is called when declared.
console.log(sum) // -> 15

3. Mutate observed properties

// calculateSum will be called each time one of its dependencies has changed.

object.one = 2
console.log(sum) // -> 16
array[0]++
console.log(sum) // -> 17

array.unshift(1)
console.log(sum) // -> 18
array.shift()
console.log(sum) // -> 17

4. Release computed functions

// Observed objects store computed function references in a Set,
// which prevents garbage collection as long as the object lives.
// Calling dispose allows the function to be garbage collected.
dispose(calculateSum)

Add-ons

Additional features that you can import from a sub path.

A simple but clever react store.

A reactive http cache.

Utility callbacks triggered when a property is mutated.

An Observable class.

Hyperactiv websocket implementation.

Code samples

A simple sum and a counter

// Observe an object and its properties.
const obj = observe({
    a: 1,
    b: 2,
    sum: 0,
    counter: 0
})

// The computed function auto-runs by default.
computed(() => {
    // This function depends on a, b and counter.
    obj.sum = obj.a + obj.b
    // It also sets the value of counter, which is circular (get & set).
    obj.counter++
})

// The function gets executed when computed() is called…
console.log(obj.sum)     // -> 3
console.log(obj.counter) // -> 1
obj.a = 2
// …and when a or b are mutated.
console.log(obj.sum)     // -> 4
console.log(obj.counter) // -> 2
obj.b = 3
console.log(obj.sum)     // -> 5
console.log(obj.counter) // -> 3

Nested functions

const obj = observe({
    a: 1,
    b: 2,
    c: 3,
    d: 4,
    totalSum: 0
})

const aPlusB = () => {
    return obj.a + obj.b
}
const cPlusD = () => {
    return obj.c + obj.d
}

// Depends on a, b, c and d.
computed(() => {
    obj.totalSum = aPlusB() + cPlusD()
})

console.log(obj.totalSum) // -> 10
obj.a = 2
console.log(obj.totalSum) // -> 11
obj.d = 5
console.log(obj.totalSum) // -> 12

Chaining computed properties

const obj = observe({
    a: 0,
    b: 0,
    c: 0,
    d: 0
})

computed(() => { obj.b = obj.a * 2 })
computed(() => { obj.c = obj.b * 2 })
computed(() => { obj.d = obj.c * 2 })

obj.a = 10
console.log(obj.d) // -> 80

Asynchronous computations

// Promisified setTimeout.
const delay = time => new Promise(resolve => setTimeout(resolve, time))

const obj = observe({ a: 0, b: 0, c: 0 })
const multiply = () => {
    obj.c = obj.a * obj.b
}
const delayedMultiply = computed(

    // When dealing with asynchronous functions
    // wrapping with computeAsync is essential to monitor dependencies.

    ({ computeAsync }) =>
        delay(100).then(() =>
            computeAsync(multiply)),
    { autoRun: false }
)

delayedMultiply().then(() => {
    console.log(obj.b) // -> 0
    obj.a = 2
    obj.b = 2
    console.log(obj.c) // -> 0
    return delay(200)
}).then(() => {
    console.log(obj.c) // -> 4
})

Batch computations

// Promisified setTimeout.
const delay = time => new Promise(resolve => setTimeout(resolve, time))

// Enable batch mode.
const array = observe([0, 0, 0], { batch: true })

let sum = 0
let triggerCount = 0

const doSum = computed(() => {
    ++triggerCount
    sum = array.reduce((acc, curr) => acc + curr)
})

console.log(sum) // -> 0

// Even if we are mutating 3 properties, doSum will only be called once asynchronously.

array[0] = 1
array[1] = 2
array[2] = 3

console.log(sum) // -> 0

delay(10).then(() => {
    console.log(`doSum triggered ${triggerCount} time(s).`) // -> doSum triggered 2 time(s).
    console.log(sum) // -> 6
})

Observe only some properties

const object = {
    a: 0,
    b: 0,
    sum: 0
}

// Use props to observe only some properties
// observeA reacts only when mutating 'a'.

const observeA = observe(object, { props:  ['a'] })

// Use ignore to ignore some properties
// observeB reacts only when mutating 'b'.

const observeB = observe(object, { ignore: ['a', 'sum'] })

const doSum = computed(function() {
    observeA.sum = observeA.a + observeB.b
})

// Triggers doSum.

observeA.a = 2
console.log(object.sum) // -> 2

// Does not trigger doSum.

observeA.b = 1
observeB.a = 1
console.log(object.sum) // -> 2

// Triggers doSum.

observeB.b = 2
console.log(object.sum) // -> 3

Automatically bind methods

let obj = new SomeClass()
obj = observe(obj, { bind: true })
obj.someMethodThatMutatesObjUsingThis()
// observe sees all!

This and class syntaxes

class MyClass {
    constructor() {
        this.a = 1
        this.b = 2

        const _this = observe(this)

        // Bind computed functions to the observed instance.
        this.doSum = computed(this.doSum.bind(_this))

        // Return an observed instance.
        return _this
    }

    doSum() {
        this.sum = this.a + this.b
    }
}

const obj = new MyClass()
console.log(obj.sum) // -> 3
obj.a = 2
console.log(obj.sum) // -> 4
const obj = observe({
    a: 1,
    b: 2,
    doSum: function() {
        this.sum = this.a + this.b
    }
}, {
    // Use the bind flag to bind doSum to the observed object.
    bind: true
})

obj.doSum = computed(obj.doSum)
console.log(obj.sum) // -> 3
obj.a = 2
console.log(obj.sum) // -> 4

API

observe

Observes an object or an array and returns a proxified version which reacts on mutations.

observe(Object | Array, {
    props: String[],
    ignore: String[],
    batch: boolean,
    deep: boolean = true,
    bind: boolean
}) => Proxy

Options

  • props: String[]

Observe only the properties listed.

  • ignore: String[]

Ignore the properties listed.

  • batch: boolean | int

Batch computed properties calls, wrapping them in a setTimeout and executing them in a new context and preventing excessive calls. If batch is an integer greater than zero, the calls will be debounced by the value in milliseconds.

  • deep: boolean

Recursively observe nested objects and when setting new properties.

  • bind: boolean

Automatically bind methods to the observed object.

computed

Wraps a function and captures observed properties which are accessed during the function execution. When those properties are mutated, the function is called to reflect the changes.

computed(fun: Function, {
    autoRun: boolean,
    callback: Function
}) => Proxy

Options

  • autoRun: boolean

If false, will not run the function argument when calling computed(function).

The computed function must be called at least once to calculate its dependencies.

  • callback: Function

Specify a callback that will be re-runned each time a dependency changes instead of the computed function.

dispose

Will remove the computed function from the reactive Maps (the next time an bound observer property is called) allowing garbage collection.

dispose(Function) => void
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].