
Product
Introducing Socket Scanning for OpenVSX Extensions
Socket now scans OpenVSX extensions, giving teams early detection of risky behaviors, hidden capabilities, and supply chain threats in developer tools.
kr-observable
Advanced tools
Proxy based state-manager
import { Observable, observer } from "kr-observable";
class State extends Observable {
results: string[] = []
text = ''
loading = false
// All methods are automatically bounded,
// so you can safely use them as listeners
setText(event: Event) {
this.text = event.target.value
}
async search() {
try {
this.loading = true
const response = await fetch('/someApi')
this.results = await response.json()
} catch(e) {
console.warn(e)
} finally {
this.loading = false
}
}
reset() {
this.results = []
}
}
const state = new State()
const Results = observer(function results() {
// Will re-render only if the results change
return (
<div>
{state.results.map(result => <div key={result}>{result}</div>)}
</div>
)
})
const Component = observer(function component() {
// Will re-render only if the text or loading change
return (
<div>
<input
placeholder="Text..."
onChange={state.setText}
disabled={state.loading}
value={state.text}
/>
<button
onClick={state.search}
disabled={state.loading}
>
Submit
</button>
<button onClick={state.reset}>
Reset
</button>
<Results />
</div>
)
})
More complicated example on CodeSandbox
The observer converts a React component into a reactive component, which tracks observables and re-renders the component when one of these changes.
Can only be used for function components.
interface Options {
// optional FC debug name
name?: string
// if true, debug info will be printed to console on each render/re-render
// icluding renders count and re-render reasons (i.e changed observables)
debug?: boolean
}
type observer<P> = (baseComponent: FunctionComponent<P>, options?: Options) => FunctionComponent<P>
import { Observable } from 'kr-observable'
class Foo extends Observable { }
bounded by defaultlisten, unlisten, subscribe and unsubscribe are reserved. They won't work even on accidentally redefine.
Their signature below.type Subscriber = (property: string | symbol, value: any) => void
type Listener = () => void
interface Observable {
// The callback will be triggered on each change
listen(cb: Listener): void
// remove listener
unlisten(cb: Listener): void
// The callback will be triggered on each "batch"
// i.e. some part of changes made almost at the same time,
// for the properties passed as second argument
subscribe(cb: Subscriber, keys: Set<keyof Observable>): void
// remove subscriber
unsubscribe(cb: Subscriber): void
}
Example
import { Observable } from "kr-observable";
class Example extends Observable {
#private = 1
string = ''
number = 0
array = []
set = new Set()
map = new Map()
plain = {
foo: 'baz',
nestedArray: []
}
date = new Date()
get something() {
return this.number + this.string // computed
}
}
const example = new Example()
const listener = (property: string | symbol, value: any) => {
console.log(`${property} was changed, new value = `, value)
}
// will be called only once,
// because the changes happened (almost) at the same time
const subscriber = () => {
console.log('subscriber was notified')
}
example.listen(listener)
example.subscribe(subscriber, new Set(['string', 'number', 'array']))
example.string = 'hello' // string was changed, new value = hello
example.number = 2 // number was changed, new value = 2
// anything that mutates an Array, Map, Set or Date is considered a change
example.array.push('string') // array was changed, new value = string
example.array = [] // array was changed, new value = []
example.date.setHour(12) // date was changed, new value = 12
example.plain.foo = '' // foo was changed, new value = ''
example.plain.nestedArray.push(42) // nestedArray was changed, new value = 42
Has the same API as Observable, but works only with plain objects
import { makeObservable } from 'kr-observable';
const observableObject = makeObservable({
foo: 'bar',
count: 0,
increaseCount() {
this.count++
}
})
The autorun function accepts one function that should run every time anything it observes changes.
It also runs once when you create the autorun itself.
import { Observable, autorun } from 'kr-observable';
class Example extends Observable {
one = 0
two = 0
}
const example = new Example()
autorun(() => console.log('total', example.one + example.two))
setInterval(() => {
example.one += 1 // total {number}
}, 1000)
There is only one limitation: if you assign a new element to the array by index – changes will happen, of course, but You will not be notified.
import { Observable } from 'kr-observable';
class Example extends Observable {
array = []
}
const state = new Example()
state.listen((p,v) => console.log(p,v))
state.array[0] = 1 //
state.set(0,1) // array 1
There is a new set method in Array which you can use for that.
FAQs
Adds reactivity power for your JavaScript
We found that kr-observable demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Socket now scans OpenVSX extensions, giving teams early detection of risky behaviors, hidden capabilities, and supply chain threats in developer tools.

Product
Bringing supply chain security to the next generation of JavaScript package managers

Product
A safer, faster way to eliminate vulnerabilities without updating dependencies