@ts-livedata/react
v0.1.0-alpha01
Published
A TypeScript LiveData library with React Hooks
Downloads
4
Maintainers
Readme
TS LiveData React Library
About
Observer pattern based library for React, similar to Android's LiveData.
For information on the Observer pattern please visit Wikipedia.
Includes @ts-livedata/core separately to reduce dependency trees.
Installation
npm install @ts-livedata/react
yarn add @ts-livedata/react
Usage
// View.tsx
import * as React from "react"
import {HookLiveData} from "@ts-livedata/react"
export class ViewModel {
// our value for presentation
count: number
// our LiveData for observing changes to `count`
countLiveData: HookLiveData<number>
// our LiveData for observing loading state
loadingLiveData: HookLiveData<boolean>
constructor() {
this.countLiveData = new HookLiveData<number>()
this.loadingLiveData = new HookLiveData<boolean>()
this.count = 0
}
doSomethingInBackground() {
// do some heavy lifting in background, set loading to true
this.loadingLiveData.postValue(true)
setTimeout(() => {
this.count += 1
this.countLiveData.postValue(this.count)
this.loadingLiveData.postValue(false)
}, 1000)
}
}
const viewModel = new ViewModel()
export const View = () => {
// Need useState hook to tell React to re-render component with our new data
const [count, setCount] = React.useState<number>(0)
const [loading, setLoading] = React.useState<boolean>(false)
// observe our LiveData's, this will auto-remove observer on component unmount
viewModel.countLiveData.observe((x: number) => {
setCount(x)
})
viewModel.loadingLiveData.observe((x: boolean) => {
setLoading(x)
})
return (
<div>
{/* when click do something in background */}
<button onClick={() => viewModel.doSomethingInBackground()}>Click me</button>
{/* the value of count */}
<h2>{count}</h2>
{/* show a small loader when true*/}
{loading ? <div>loading</div> : null}
</div>
)
}
// View.spec.tsx
import {expect} from "chai"
import {renderHook} from "@testing-library/react-hooks"
import {ViewModel} from "./View"
jest.useFakeTimers()
describe("ViewModel", () => {
it("should update hook and remove observer once unmounted", () => {
// Given
const expectedCount = 1
const viewModel = new ViewModel()
// simpler to test returning promise with resolve on observed value
const {result, unmount} = renderHook(() => {
return new Promise<number>(resolve => {
viewModel.countLiveData.observe((count: number) => {
resolve(count)
})
})
})
// When
viewModel.doSomethingInBackground()
jest.advanceTimersByTime(1000)
// Then
result.current.then(actual => {
expect(actual).equal(expectedCount)
})
let observers = viewModel.countLiveData.getObservers()
expect(observers).length(1)
unmount()
observers = viewModel.countLiveData.getObservers()
expect(observers).length(0)
})
})
Questions
Feel free to drop a Github issue with any questions you may have.
License
This project is licensed under the terms of the Apache 2.0 license.