# 简单例子
# 条件渲染(原生 JavaScript 例子)
使用 observable-hooks 你甚至可以得到 React 元素流。如果想用 Suspense 可以看看 Render-as-You-Fetch (using Suspense)。
这会影响到虚拟 DOM 么?不会的,React 元素都是普通对象。 实际上重新渲染时这会比使用 Suspense 或错误边界要快,因为:
- 它不需要
throw
并依赖try
和catch
。但当然后者这么做可以支持类似 Context 的使用。 - React 重新渲染父组件的时侯不需要对没有用到的分支也重新计算一遍。甚至如果没有新的值产生子组件都不会被重新渲染。它就像一层天然的缓存。
import { from, of } from 'rxjs'
import { map, switchMap, startWith, catchError } from 'rxjs/operators'
import { useObservableState } from 'observable-hooks'
import { fetchData } from './api'
import { DefaultUI, SuccessUI, LoadingUI, FailedUI } from './components'
export function App() {
const [status, onFetchData] = useObservableState(
event$ => event$.pipe(
// OMG I don't have to deal with race condition
switchMap(event =>
from(fetchData(event.currentTarget.id)).pipe(
map(value => <SuccessUI value={value} />),
// handle errors on sub-stream so that main stream stays alive
catchError(error => of(<FailedUI error={error} />)),
// show loading state immediately
startWith(<LoadingUI />)
)
)
),
() => <DefaultUI /> // initial state
)
return (
<div>
<button id="data1" onClick={onFetchData}>fetch</button>
{status}
</div>
)
}
# 防抖输入校验(原生 JavaScript 例子)
import React from 'react'
import PropTypes from 'prop-types'
import { withLatestFrom, switchMap, debounceTime, pluck } from 'rxjs/operators'
import { useObservable, useObservableState, pluckFirst } from 'observable-hooks'
const checkText = (text, uuid) =>
fetch(`https://api/${text}?uuid=${uuid}`)
.then(response => response.ok)
.catch(() => false)
export const App = props => {
// `pluckFirst` 是一个简单的辅助方法
// 相当于 `inputs$ => inputs$.pipe(map(inputs => inputs[0]))`
const uuid$ = useObservable(pluckFirst, [props.uuid])
const [isValid, onChange] = useObservableState(
event$ =>
event$.pipe(
// React 合成事件对象会被自动回收
// 先把值取出来
pluck('currentTarget', 'value'),
debounceTime(400),
withLatestFrom(uuid$),
switchMap(([text, uuid]) => checkText(text, uuid))
),
false
)
return (
<>
<input onChange={onChange} />
<button type="submit" disabled={!isValid}>
Submit
</button>
</>
)
}
App.propTypes = {
uuid: PropTypes.string
}
# 自动取消(TypeScript 例子)
import React, { FC, useState } from 'react'
import { timer, empty } from 'rxjs'
import { switchMap, mapTo } from 'rxjs/operators'
import { useObservable, useSubscription } from 'observable-hooks'
const sendBeacon = (beacon: string) => fetch(`https://api?beacon=${beacon}`)
export interface AppProps {
beacon: string
}
export const App: FC<AppProps> = props => {
const [shouldSendBeacon, setShouldSendBeacon] = useState(false)
const beacon$ = useObservable(
inputs$ =>
inputs$.pipe(
// auto-cancelation
switchMap(([shouldSendBeacon, beacon]) =>
shouldSendBeacon ? timer(1000).pipe(mapTo(beacon)) : empty()
)
),
[shouldSendBeacon, props.beacon]
)
useSubscription(beacon$, sendBeacon)
return (
<label>
<input
type="checkbox"
checked={shouldSendBeacon}
onChange={e => setShouldSendBeacon(e.currentTarget.checked)}
/>
Should Send Beacon
</label>
)
}