0.1.5 • Published 3 months ago

atomi v0.1.5

Weekly downloads
-
License
MIT
Repository
github
Last release
3 months ago

atomi

A reactivity framework.

Installation

npm i atomi

Example

import { atom, reactive } from "atomi"

const [counter, setCounter, setCounterFn] = atom(0)

reactive(() => {
  console.log(`counter is: ${counter()}`)
})

await setCounter(1) // Logs `counter is: 1`
await setCounterFn(count => count + 1) // Logs `counter is: 2`

References

Hooks

This is the part that majority of users are going to interact with.

reactive

import { reactive } from "atomi"

Used to create reactive functions. Reactive functions are such functions that execute automatically when atoms inside them change their value

ArgumentTypeDesc
callback[async] FunctionCalled when atoms inside change Accepts a single argument scope
ignoreAsyncBooleanBy default is false. If true is passed return will be always scope even if callback resovles into Promise

Returns scope or Promise that resolves into scope when callback is async or returns Promise

reactive(scope => {
  const value = dependantAtom()
  scope.stop()
})

atom

  • src/hooks.mjs#82
  • Accept Any
  • Return [() => Any, (value) => Promise, (Function) => Promise]
import { atom } from "atomi"

Atoms are used to store information. When they are accessed from inside reactive functions, atom registers function's scope as dependency. Any time atom is updated, it's functions of dependant scopes are executed.

ArgumentTypeDesc
Default ValueAnyIntial value of atom

Returns Array of getter, setter and callback setter functions

  • getter function that returns current value of the atom and registers current scope as dependecy if current scope exists
  • setter function accepts a value that will become new value of the atom. Returns a Promise that fulfills when all dependant scopes of the atom are executed
  • callback setter accepts a callback function that accepts 2 arguments and that returns new value for the atom or NONE. Returns a Promise that fulfills when all dependant scopes of the atom are executed

callback setter

ArgumentTypeDesc
Current ValueAnyThe current value of atom
NONESymbolUnique symbol. If NONE is returned the atom retains it's value and reactive updates will not follow

Returns Any or NONE

const [count, setCount, setCountFn] = atom(0)
reactive(function logCount() {
  // getter function
  console.log(count())
})
// setter function
await setCount(2)
// callback setter function
await setCountFn((current, NONE) => current + 1) // Sets count to 3 and triggers logCount to execute
await setCountFn((current, NONE) => NONE) // Count stays at 3 and logCount is not triggered.
// NONE is useful when the complex logic produces the same value as current
// and hence we do not want to update anything because it says the same.

new atom

import { atom } from "atomi"
ArgumentTypeDesc
Default ValueAnyIntial value of atom

Returns RectiveVar with default value

const count = new atom(0)
reactive(function logCount() {
  console.log(count.get())
})
await count.set(1) // sets atom count value to 1 and triggers logCount

nonreactive

import { nonreactive } from "atomi"

Used as wrapper around an atom to access its value, but not register current scope as its dependency

ArgumentTypeDesc
CallbackFunctionGetter function or atomic function

Returns the return value of the callback function

const [count, setCount] = atom(0)
const [increment, setIncrement] = atom(1)
reactive(() => {
  console.log(`count is ${count() + nonreactive(increment)}`)
})

await setCount(current => 1) // triggers the reactive function and logs `count is 2`
await setIncrement(2) // does not trigger the reactive function
await setCount(current => 2) // triggers the reactive function and logs `count is 4`

guard

import { guard } from "atomi"

Used as wrapper around an atom or a function to access its value, but triggers value changes. Acceps a comparison function as a second argument.

ArgumentTypeDesc
CallbackFunctionGetter function or atomic function
ComparatorFunctionComparator function; accepts 2 arguments, new and old return value of the callback function. Will trigger the dependencies and store the new value when Comparator returns true

Returns the return value of the callback function

const [number, setNumber] = atom(0)
reactive(() => {
  console.log(`number is ${guard(number)}`)
})

await setNumber(1) // triggers the reactive function and logs `count is 1`
await setNumber(1) // does not trigger the reactive function
await setNumber(2) // triggers the reactive function and logs `count is 2`

Example using custom comparator function:

const [number, setNumber] = atom(0)
reactive(() => {
  console.log(`number is ${guard(number, (a, b) => parseInt(a) !== parseInt(b))}`)
})

await setNumber(0.5) // does not trigger the reactive function, because parseInt(0.5) is still 0
await setNumber(1.1) // triggers the reactive function and logs `count is 1.1`
await setNumber(1.5) // does not trigger the reactive function, because parseInt(1.5) is still 1

Core

This part describes the core functionality that the framework is built upon. Majority of users should not interact with it directly unless working on a library that extends core functionalities.

ReactiveVar

A class that is used by atoms internally to store value.

NOTE: it is recommended to use atoms in your work, unless you are working on a library or you like the syntax of it better. If you prefer to use ReactiveVar directly for OOP style programming, you still should use new atom instead

import { ReactiveVar } from "atomi"

#get

Returns current value of the ReactiveVar and registers current scope as a dependency is current scope exists

const counter = new atom(0)
reactive(() => {
  const count = counter.get()
  ...
})

#set

Sets value of the ReactiveVar

const counter = new atom(0)
counter.set(2) // counter.get will return 2 instead

Scope

A class that manages reactive functions

import { Scope } from "atomi"
ArgumentTypeDesc
CallbackFunctionThe function that we with to execute when inside update

reactive passes scope to the callback fucntion and returns the same scope

const scope = reactive(scope => {
  console.log(scope.firstRun) // logs: true
})

scope.die()

#depend

Is used by ReactiveVar.get to register a dependency

die

Intended to be used like #stop but permanently

#execute

Is used by Tracker when to execute reactive function when Scope was triggered by any ReactiveVars previously

#firstRun

A getter property of Scope. Returns true if the dependant function has not been called more then once.

reactive(scope => {
  console.log(scope.firstRun) // logs: true
})

#resume

Is used to restore connection between dependant ReactiveVars and the Scope. Should be called to restore reactive function execution after Scope.stop had been called.

const [count, setCount] = atom(0)
const scope = reactive(scope => {
  console.log(`count is ${count()}`)
})
await setCount(1) // logs `count is 1`
scope.stop()
await setCount(2) // does not log anything
scope.resume()
await setCount(3) // logs `count is 3`

#stop

Is used when we want to temporary suspend reactive function execution event when its dependencies are updated.

const [count, setCount] = atom(0)
const scope = reactive(scope => {
  console.log(`count is ${count()}`)
})
await setCount(1) // logs `count is 1`
scope.stop()
await setCount(2) // does not log anything
scope.resume()
await setCount(3) // logs `count is 3`

#trigger

Is used by ReactiveVar when setting a new value.

Returns Promise that fullfils when reactive function of the scope is finished executing

#triggeredBy

Is a property of the scope. Is usefull when debugging to know what ReactiveVar triggered the scope update when scope depends on multiple ReactiveVars

Tracker

Intended to be used as a global object to track and register ReactiveVar updates and execute reactive functions

import { Tracker } from "atomi"

scheduleJob

Schedules scope's reactive function to execute when callback queue is empty. Is used by Scope.trigger to schedule function execution when dependant ReactiveVars update.

Usefull functions

This sections will focus exclusively on the functions to enhance experience with using atoms Specifically on the (callback setter)[#callback-setter) part of it. All of the following functions shine when used in combination with the callback setter

Numbers

add

Creates and adder function

import { add } from "atomi"
const [count,, setCount] = atom(0)

setCount(add(2)) // sets 2 as count value
setCount(add(5)) // sets 7 as count value

sub

Creates and subtractor function

import { sub } from "atomi"
const [count,, setCount] = atom(10)

setCount(sub(2)) // sets 8 as count value
setCount(sub(5)) // sets 3 as count value

inc

Is an edge case of add function that uses 1 as its argument

import { inc } from "atomi"
const [count,, setCount] = atom(0)

setCount(inc) // sets 1 as count value
setCount(inc) // sets 2 as count value

dec

Is an edge case of sub function that uses 1 as its argument

import { sub } from "atomi"
const [count,, setCount] = atom(10)

setCount(sub) // sets 9 as count value
setCount(sub) // sets 8 as count value

power

Creates power function

import { pow } from "atomi"
const [count,, setCount] = atom(2)

setCount(pow(2)) // sets 4 as count value
setCount(pow(3)) // sets 64 as count value

Objects

assign

Creates assigner function

import { assign } from "atomi"
const [person,, setPerson] = atom({ name: "tim" })

setPerson(assing({ age: 22 })) // sets person to be { name: "tim", age: 22 }
setPerson(assing({ age: 23 })) // sets person to be { name: "tim", age: 23 }

Booleans

not

Should be self explanatory

import { not } from "atomi"
const [state,, setState] = atom(true)

setState(not) // sets state to false
setState(not) // sets state to true

id

Good old identity function

import { id } from "atomi"
const [array,, setArray] = atom([1,0,2,0])

setArray(filter(id)) // filters out all falsy values leaving [1, 2]

is

Good old identity function

import { is } from "atomi"
const [array,, setArray] = atom([1,0,1,2,0])

setArray(filter(is(1))) // filters out all values that are not 1 leaving [1, 1]

lesser

Creates function that check if value is lesser then provided

import { lesser } from "atomi"
const [array,, setArray] = atom([1,0,1,2,0])

setArray(filter(lesser(2))) // filters all values that less then 2 [1,0,1,0]

greater

Creates function that check if value is lesser then provided

import { greater } from "atomi"
const [array,, setArray] = atom([1,0,1,2,0])

setArray(filter(greater(1))) // filters all values that are greater then 1 leaving [2]

negative

Is an edge case of lesser function that uses 1 as its argument

import { negative } from "atomi"
const [array,, setArray] = atom([-1,0,1,2,0])

setArray(filter(negative)) // filters out all values that are not negative leaving [-1]

positive

Is an edge case of greater function that uses 1 as its argument

import { positive } from "atomi"
const [array,, setArray] = atom([-1,0,1,2,0])

setArray(filter(positive)) // filters out all values that are not negative leaving [1,2]

Arrays

map

Creates a mapper

import { map } from "atomi"
const [array,, setArray] = atom([1,3,2])

setArray(map(x => x + 1)) // increases all array elements by 1
setArray(map(inc)) // increases all array elements by 1 using inc

filter

Creates a filterer

import { filter } from "atomi"
const [array,, setArray] = atom([1,3,2])

setArray(filter(x => x > 1)) // keeps only elemens that are larger then 1

prepend

Creates a prepender

import { prepend } from "atomi"
const [array,, setArray] = atom([1,3,2])

setArray(prepend(0, 0.5)) // adds 0 and 0.5 at the beginning. Not array is [0,0.5,1,3,2]

append

Creates a appender

import { append } from "atomi"
const [array,, setArray] = atom([1,3,2])

setArray(append(0)) // add 0 at the end. Not array is [1,3,2,0]

insert

Creates a inserter

import { insert } from "atomi"
const [array,, setArray] = atom([1,3,2])

setArray(insert(1, 4, 5)) // inserted [4, 5] at position 1. Now array stores [1, 4, 5, 3, 2]

assignWhere

Creates a function that will update specific element in the array

import { assignWhere } from "atomi"
const [array,, setArray] = atom([1,3,2])

setArray(assignWhere(is(3)), inc) // where element is equal to 3 it will increases it by 1. Now array stores [1,4,2]

sort

Creates a function that will sort an array based on the sorter provided when passed to a callback setter

import { sort } from "atomi"
const [array,, setArray] = atom([11,1,3,2])

setArray(sort()) // using default js sorter. Now array stores [1, 11, 2, 3]

asc

Precoded sorter to sort by ascending order

import { asc } from "atomi"
const [array,, setArray] = atom([11,1,3,2])

setArray(sort(asc)) // using default js sorter. Now array stores [1, 2, 3, 11]

desc

Precoded sorter to sort by descending order

import { desc } from "atomi"
const [array,, setArray] = atom([11,1,3,2])

setArray(sort(desc)) // using default js sorter. Now array stores [11, 3, 2, 1]
0.1.4

3 months ago

0.1.5

3 months ago

0.1.3

3 months ago

0.1.0

12 months ago

0.1.2

12 months ago

0.1.1

12 months ago

0.0.3

1 year ago

0.0.2

1 year ago

0.0.1

1 year ago