Skip to content

Commit

Permalink
recipes/invalidate-query
Browse files Browse the repository at this point in the history
  • Loading branch information
voliva committed May 7, 2021
1 parent 38d74ea commit ea6be45
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 6 deletions.
74 changes: 74 additions & 0 deletions docs/examples/InvalidateQuery.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { bind, Subscribe } from "@react-rxjs/core"
import { createSignal } from "@react-rxjs/utils"
import React, { useRef } from "react"
import { concat, defer } from "rxjs"
import { concatMap, switchMap } from "rxjs/operators"

const { getTodos, postTodo } = (() => {
let todos = [
{
id: 0,
title: "Grocery shopping",
},
]

return {
getTodos: async () => todos,
postTodo: async (todo) => {
todos = [
...todos,
{
id: todos[todos.length - 1].id + 1,
title: todo,
},
]
},
}
})()

const [todoPost$, addTodo] = createSignal<string>()

const todoResult$ = todoPost$.pipe(concatMap(postTodo))

const [useTodos] = bind(
// When do we need to request todos?
concat(
// 1. One single time when starting
defer(getTodos),
// 2. Every time we have created a new todo
todoResult$.pipe(switchMap(getTodos)),
),
[],
)

function Todos() {
const todos = useTodos()

const ref = useRef<HTMLInputElement>()
const handleAddClick = () => {
addTodo(ref.current!.value)
ref.current!.value = ""
ref.current!.focus()
}

return (
<div>
<input type="text" defaultValue="Do Laundry" ref={ref} />
<button onClick={handleAddClick}>Add Todo</button>

<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
</div>
)
}

export default function InvalidateQuery() {
return (
<Subscribe fallback={<div>Loading...</div>}>
<Todos />
</Subscribe>
)
}
5 changes: 2 additions & 3 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ title: Features
- Simplifies code navigability.
- First-class support for React Suspense.
- First-class support for Error boundaries.
- No centralized store.
- No state context provider.
- Completely decentralized store.
- Built in Typescript.
- Works with React DOM and React Native.
- Works with any React renderer (React DOM, React Native, etc.).
- No external dependencies.
- Extremely light: 3.4kB parsed, 1.5kB gziped.
- Thin API.
6 changes: 3 additions & 3 deletions docs/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { bind, Subscribe } from "@react-rxjs/core"
import { createSignal } from "@react-rxjs/utils"

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

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

The interactive result:
### Interactive result

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

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

React-RxJS gets even more fun when you start using asynchronous state, leveraging Suspense and enhancing code-splitting!
React-RxJS gets even more fun when you start using asynchronous state, leveraging Suspense and enhancing code-splitting!
71 changes: 71 additions & 0 deletions docs/recipes/invalidate-query.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
title: Invalidate Query
---

import InvalidateQuery from "../examples/InvalidateQuery"
import BrowserOnly from '@docusaurus/BrowserOnly';

```tsx
import { bind, Subscribe } from "@react-rxjs/core"
import { createSignal } from "@react-rxjs/utils"
import { concat, defer } from "rxjs"
import { concatMap, switchMap } from "rxjs/operators"
import { getTodos, postTodo } from "../my-api"

const [todoPost$, addTodo] = createSignal<string>()

const todoResult$ = todoPost$.pipe(
concatMap(postTodo)
)

const [useTodos] = bind(
// When do we need to request todos?
concat(
// 1. One single time when starting
defer(getTodos),
// 2. Every time we have created a new todo
todoResult$.pipe(
switchMap(getTodos)
)
),
[]
)

function Todos() {
const todos = useTodos()

const ref = useRef<HTMLInputElement>()
const handleAddClick = () => {
addTodo(ref.current!.value)
ref.current!.value = ""
ref.current!.focus()
}

return (
<div>
<input type="text" defaultValue="Do Laundry" ref={ref} />
<button onClick={handleAddClick}>Add Todo</button>

<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
</div>
)
}

function App() {
return (
<Subscribe>
<Todos />
</Subscribe>
)
}
```

### Interactive result

<BrowserOnly>
{() => <InvalidateQuery />}
</BrowserOnly>
1 change: 1 addition & 0 deletions sidebars.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
someSidebar: {
Introduction: ["motivation", "quick-start", "features"],
Recipes: ["recipes/invalidate-query"],
"API Reference": [
{
type: "category",
Expand Down

0 comments on commit ea6be45

Please sign in to comment.