Skip to content

Commit ea6be45

Browse files
committed
recipes/invalidate-query
1 parent 38d74ea commit ea6be45

File tree

5 files changed

+151
-6
lines changed

5 files changed

+151
-6
lines changed

docs/examples/InvalidateQuery.tsx

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { bind, Subscribe } from "@react-rxjs/core"
2+
import { createSignal } from "@react-rxjs/utils"
3+
import React, { useRef } from "react"
4+
import { concat, defer } from "rxjs"
5+
import { concatMap, switchMap } from "rxjs/operators"
6+
7+
const { getTodos, postTodo } = (() => {
8+
let todos = [
9+
{
10+
id: 0,
11+
title: "Grocery shopping",
12+
},
13+
]
14+
15+
return {
16+
getTodos: async () => todos,
17+
postTodo: async (todo) => {
18+
todos = [
19+
...todos,
20+
{
21+
id: todos[todos.length - 1].id + 1,
22+
title: todo,
23+
},
24+
]
25+
},
26+
}
27+
})()
28+
29+
const [todoPost$, addTodo] = createSignal<string>()
30+
31+
const todoResult$ = todoPost$.pipe(concatMap(postTodo))
32+
33+
const [useTodos] = bind(
34+
// When do we need to request todos?
35+
concat(
36+
// 1. One single time when starting
37+
defer(getTodos),
38+
// 2. Every time we have created a new todo
39+
todoResult$.pipe(switchMap(getTodos)),
40+
),
41+
[],
42+
)
43+
44+
function Todos() {
45+
const todos = useTodos()
46+
47+
const ref = useRef<HTMLInputElement>()
48+
const handleAddClick = () => {
49+
addTodo(ref.current!.value)
50+
ref.current!.value = ""
51+
ref.current!.focus()
52+
}
53+
54+
return (
55+
<div>
56+
<input type="text" defaultValue="Do Laundry" ref={ref} />
57+
<button onClick={handleAddClick}>Add Todo</button>
58+
59+
<ul>
60+
{todos.map((todo) => (
61+
<li key={todo.id}>{todo.title}</li>
62+
))}
63+
</ul>
64+
</div>
65+
)
66+
}
67+
68+
export default function InvalidateQuery() {
69+
return (
70+
<Subscribe fallback={<div>Loading...</div>}>
71+
<Todos />
72+
</Subscribe>
73+
)
74+
}

docs/features.md

+2-3
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ title: Features
77
- Simplifies code navigability.
88
- First-class support for React Suspense.
99
- First-class support for Error boundaries.
10-
- No centralized store.
11-
- No state context provider.
10+
- Completely decentralized store.
1211
- Built in Typescript.
13-
- Works with React DOM and React Native.
12+
- Works with any React renderer (React DOM, React Native, etc.).
1413
- No external dependencies.
1514
- Extremely light: 3.4kB parsed, 1.5kB gziped.
1615
- Thin API.

docs/quick-start.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import { bind, Subscribe } from "@react-rxjs/core"
2828
import { createSignal } from "@react-rxjs/utils"
2929

3030
// A signal is an entry point to react-rxjs. It's equivalent to using a subject
31-
const [textChange$, setText] = createSignal();
31+
const [textChange$, setText] = createSignal<string>()
3232

3333
// bind returns a hook to get the value of the observable.
3434
const [useText, text$] = bind(textChange$, "")
@@ -79,7 +79,7 @@ function CharacterCounter() {
7979
}
8080
```
8181

82-
The interactive result:
82+
### Interactive result
8383

8484
<BrowserOnly>
8585
{() => <CharacterCounter />}
@@ -89,4 +89,4 @@ The interactive result:
8989

9090
This is just a simple example of two components sharing a synchronous state.
9191

92-
React-RxJS gets even more fun when you start using asynchronous state, leveraging Suspense and enhancing code-splitting!
92+
React-RxJS gets even more fun when you start using asynchronous state, leveraging Suspense and enhancing code-splitting!

docs/recipes/invalidate-query.md

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
---
2+
title: Invalidate Query
3+
---
4+
5+
import InvalidateQuery from "../examples/InvalidateQuery"
6+
import BrowserOnly from '@docusaurus/BrowserOnly';
7+
8+
```tsx
9+
import { bind, Subscribe } from "@react-rxjs/core"
10+
import { createSignal } from "@react-rxjs/utils"
11+
import { concat, defer } from "rxjs"
12+
import { concatMap, switchMap } from "rxjs/operators"
13+
import { getTodos, postTodo } from "../my-api"
14+
15+
const [todoPost$, addTodo] = createSignal<string>()
16+
17+
const todoResult$ = todoPost$.pipe(
18+
concatMap(postTodo)
19+
)
20+
21+
const [useTodos] = bind(
22+
// When do we need to request todos?
23+
concat(
24+
// 1. One single time when starting
25+
defer(getTodos),
26+
// 2. Every time we have created a new todo
27+
todoResult$.pipe(
28+
switchMap(getTodos)
29+
)
30+
),
31+
[]
32+
)
33+
34+
function Todos() {
35+
const todos = useTodos()
36+
37+
const ref = useRef<HTMLInputElement>()
38+
const handleAddClick = () => {
39+
addTodo(ref.current!.value)
40+
ref.current!.value = ""
41+
ref.current!.focus()
42+
}
43+
44+
return (
45+
<div>
46+
<input type="text" defaultValue="Do Laundry" ref={ref} />
47+
<button onClick={handleAddClick}>Add Todo</button>
48+
49+
<ul>
50+
{todos.map((todo) => (
51+
<li key={todo.id}>{todo.title}</li>
52+
))}
53+
</ul>
54+
</div>
55+
)
56+
}
57+
58+
function App() {
59+
return (
60+
<Subscribe>
61+
<Todos />
62+
</Subscribe>
63+
)
64+
}
65+
```
66+
67+
### Interactive result
68+
69+
<BrowserOnly>
70+
{() => <InvalidateQuery />}
71+
</BrowserOnly>

sidebars.js

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module.exports = {
22
someSidebar: {
33
Introduction: ["motivation", "quick-start", "features"],
4+
Recipes: ["recipes/invalidate-query"],
45
"API Reference": [
56
{
67
type: "category",

0 commit comments

Comments
 (0)