Like Array.reduce()
but for callbags. You can use it to combine consecutive values:
1linkfunction scan<I, O>(
2link reducer: (acc: O, each: I) => O,
3link seed?: O
4link): (src: Source<I>) => Source<O>
1linkimport { of, scan, subscribe, pipe } from 'callbag-common'
2link
3linkpipe(
4link of(1, 2, 3, 4),
5link scan((fact, i) => fact * i, 1),
6link subscribe(console.log)
7link)
1
2
6
24
👉 scan()
can be used for handling pagination. Here is an example React app using
react-callbag-streams:
1linkconst [query, setQuery] = useState('')
2linkconst [loadMoreSignal, loadMore] = useSignal()
3link
4linkconst [entries, loading] = useStream(
5link query, // --> for each input query
6link filter(q => !!q), // --> that is non-empty
7link debounce(200), // --> debounce it by 200 ms to avoid spamming the API
8link map(q =>
9link pipe(
10link combine( // --> combine the query with a page number
11link of(q),
12link pipe(
13link loadMoreSignal, // --> for each signal for loading more data
14link scan(p => ++p, 0), // --> increase the page number
15link startWith(0), // --> starting with 0
16link ),
17link ),
18link map(([q, p]) => fromPromise(fetch(q, p))), // --> fetch data for given query and page number
19link flatten, // --> flatten the request
20link scan((all, page) => [...all, ...page], []), // --> accumulate received entries
21link )
22link ),
23link flatten
24link)
25link
26linkreturn (
27link <>
28link <input onInput={e => setQuery((e.target as any).value)}/>
29link { entries.map( entry => <div key={entry}>{entry}</div> }
30link <br/>
31link <button onClick={() => loadMore()}>Load More</button>
32link </>
33link)
👉 scan()
can also be used for Redux-style state management:
1linkconst state = pipe(
2link dispatch,
3link scan(
4link (state, action) => { // --> this is the reducer
5link if (action.type === 'INSERT') {
6link state.todos.push(action.todo)
7link } else if (action.type === 'CLEAR') {
8link state.todos = []
9link }
10link
11link return state
12link },
13link { todos: [] } // --> this is the initial state
14link )
15link)