Skip to content

Commit 7d57039

Browse files
volivajosepot
authored andcommitted
Improve doc around factory bind
1 parent 064c8b8 commit 7d57039

File tree

2 files changed

+30
-6
lines changed

2 files changed

+30
-6
lines changed

docs/api/core/bind.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ function bind<A extends unknown[], O>(
6666
- `getObservable`: Factory of Observables. The arguments of this function
6767
will be the ones used in the hook.
6868

69+
:::note
70+
It's important that the observable returned by `getObservable` shouldn't make the side-effect (or request) on subscription - Instead, it should take the needed value from other existing streams. See [Core Concepts - instances](core-concepts.md#instances) for more info
71+
:::
72+
6973
#### Returns
7074

7175
`[1, 2]`:

docs/core-concepts.md

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,10 @@ Now, where does data for the state come from? Probably the first example that we
157157
import { ajax } from "rxjs/ajax"
158158
import { bind } from "@react-rxjs/core"
159159

160-
const [usePost, post$] = bind((id: string) => ajax.getJSON("/posts/" + id))
160+
const [useTodos, todo$] = bind(ajax.getJSON("/todos"))
161161
```
162162

163-
And of course, this will work: Any component can use `usePost` to fetch the post of a specific id.
163+
And of course, this will work: Any component can use `useTodos` to get the list of todos.
164164

165165
However, there are some times where we need to use data coming directly from the user. This is where RxJS `Subject`s come into play.
166166

@@ -188,6 +188,28 @@ Keep in mind that `bind` doesn't do magic. If no one is subscribed to `todoList$
188188

189189
Remember, if you have a case like this (where you are pushing a Subject but no one is subscribed to those changes), make sure you have an active subscription to the stream by using `<Subscribe source$={stream} />` or `useSubscribe(stream)`. This way, `todoList$` will update when a new value is pushed to the subject, and the result will be replayed for every new subscriber that arrives later.
190190

191+
## Instances
192+
193+
There are many times where you need components to access a particular instance - Classic example is a list of posts. To help with that, `bind` can also take a factory function that returns an Observable for that instance.
194+
195+
However, when using this overload it's important that this observable shouldn't make the actual request, because it's hard to manage the lifecycle of these observables (when they subscribe, and when they can clean up) - Instead, it should take the value from an existing Observable-state.
196+
197+
For example, if we have a list of posts, we might have an observable that has all of them in a dictionary:
198+
199+
```ts
200+
const [usePosts, posts$] = bind(service.getPost$()) // Dictionary<Post>
201+
```
202+
203+
Although from within each instance component we could theoretically call `usePosts()`, and then take the post that component actually needs, this would cause unnecessary re-renders when other instances change. We solve this by using the factory overload:
204+
205+
```ts
206+
const [usePost, post$] = bind((id: string) =>
207+
posts$.pipe(map((posts) => posts[id])),
208+
)
209+
```
210+
211+
And now the component can use `usePost(id)` by passing it's own id, and that component will re-render only when that post changes. The second parameter returned, `post$`, it's actually also a function so that it can be composed in other streams: `post$(id)` returns the observable instance that emits Posts for that specific id.
212+
191213
## Suspense
192214

193215
In an earlier example:
@@ -196,7 +218,7 @@ In an earlier example:
196218
import { ajax } from "rxjs/ajax"
197219
import { bind } from "@react-rxjs/core"
198220

199-
const [usePost, post$] = bind((id: string) => ajax.getJSON("/posts/" + id))
221+
const [useTodos, todo$] = bind(ajax.getJSON("/todos"))
200222
```
201223

202224
You might be wondering - how does this _exactly_ work with React? If React is pull-based and it _needs_ a value at the time it's re-rendering, this stream won't have a value until the ajax call is resolved.
@@ -212,9 +234,7 @@ import { ajax } from "rxjs/ajax"
212234
import { startWith } from "rxjs/operators"
213235
import { bind } from "@react-rxjs/core"
214236

215-
const [usePost, post$] = bind((id: string) =>
216-
ajax.getJSON("/posts/" + id).pipe(startWith(null)),
217-
)
237+
const [useTodos, todos$] = bind(ajax.getJSON("/todos").pipe(startWith(null)))
218238
```
219239

220240
Now `usePost` will emit `null` immediately while it's fetching data (so that we can manually handle that), instead of suspending the component, and when the ajax call is resolved, it will emit the result of that call.

0 commit comments

Comments
 (0)