Skip to content

Commit

Permalink
Better optimized implementation of useVal
Browse files Browse the repository at this point in the history
  • Loading branch information
mweststrate committed Dec 16, 2018
1 parent f3eec99 commit e7f2aec
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 11 deletions.
41 changes: 31 additions & 10 deletions src/rval-react.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { Observable, sub, isVal, isDrv } from "rval"
import { useState, useEffect } from "react"
import { Observable, sub, isVal, isDrv, effect } from "rval"
import { useState, useEffect, useMemo } from "react"


export function useVal<T>(observable: Observable<T>): T {
if (!isVal(observable) && !isDrv(observable)) throw new Error("useval - expected val or drv")
const [val, updater] = useState(observable)
useEffect(() => {
const disposer = sub(observable, updater)
// observable has changed before effect was run first time, so trigger additional update
if (observable() !== val)
updater(observable())
return disposer
}, [observable])
let f; // forward ref to the updater function, so that we can subscribe first
// this implementation could be simpler if we would first used `useState`,
// and then set up the subscription in useEffect.
// The benefit of this setup, is that we set up the subscription first,
// so that observable is already 'hot' before we read it for the first time
// See: test "useVal - mimimum computations - 2"
const disposer = useMemo(() => sub(observable, x => f(x)), [observable])
const [val, updater] = useState(observable) // short-cut for initializer with fn: actually: () => observable()
f = updater
useEffect(() => disposer, [observable])
return val
}

Expand All @@ -23,3 +25,22 @@ export function useDrv() {
export function render() {

}

export function RValRender({ children }) {
const [tick, setTick] = useState(0)
const { render, dispose } = useMemo(() => {
let render
const dispose = effect(
children,
(didChange, pull) => {
render = pull
if (didChange()) {
setTick(tick + 1)
}
}
)
return { render, dispose }
}, [])
useEffect(() => dispose, [])
return render()
}
2 changes: 1 addition & 1 deletion tests/react.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ test('useVal - mimimum computations - 1', async () => {
expect(called).toBe(3)
})

test('useVal - mimimum computations - 1', async () => {
test('useVal - mimimum computations - 2', async () => {
const counter = val(0)
let called = 0
const doubler = drv(() => {
Expand Down

0 comments on commit e7f2aec

Please sign in to comment.