From ea6be452bc855380e55f89432b1bb20a5269c6b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Oliva?= Date: Fri, 7 May 2021 00:32:16 +0200 Subject: [PATCH] recipes/invalidate-query --- docs/examples/InvalidateQuery.tsx | 74 +++++++++++++++++++++++++++++++ docs/features.md | 5 +-- docs/quick-start.md | 6 +-- docs/recipes/invalidate-query.md | 71 +++++++++++++++++++++++++++++ sidebars.js | 1 + 5 files changed, 151 insertions(+), 6 deletions(-) create mode 100644 docs/examples/InvalidateQuery.tsx create mode 100644 docs/recipes/invalidate-query.md diff --git a/docs/examples/InvalidateQuery.tsx b/docs/examples/InvalidateQuery.tsx new file mode 100644 index 0000000..11859b1 --- /dev/null +++ b/docs/examples/InvalidateQuery.tsx @@ -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() + +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() + const handleAddClick = () => { + addTodo(ref.current!.value) + ref.current!.value = "" + ref.current!.focus() + } + + return ( +
+ + + +
    + {todos.map((todo) => ( +
  • {todo.title}
  • + ))} +
+
+ ) +} + +export default function InvalidateQuery() { + return ( + Loading...}> + + + ) +} diff --git a/docs/features.md b/docs/features.md index f8fb6da..ea76f4c 100644 --- a/docs/features.md +++ b/docs/features.md @@ -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. diff --git a/docs/quick-start.md b/docs/quick-start.md index 0852cb5..93f9f43 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -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() // bind returns a hook to get the value of the observable. const [useText, text$] = bind(textChange$, "") @@ -79,7 +79,7 @@ function CharacterCounter() { } ``` -The interactive result: +### Interactive result {() => } @@ -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! \ No newline at end of file +React-RxJS gets even more fun when you start using asynchronous state, leveraging Suspense and enhancing code-splitting! diff --git a/docs/recipes/invalidate-query.md b/docs/recipes/invalidate-query.md new file mode 100644 index 0000000..dac5ee9 --- /dev/null +++ b/docs/recipes/invalidate-query.md @@ -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() + +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() + const handleAddClick = () => { + addTodo(ref.current!.value) + ref.current!.value = "" + ref.current!.focus() + } + + return ( +
+ + + +
    + {todos.map((todo) => ( +
  • {todo.title}
  • + ))} +
+
+ ) +} + +function App() { + return ( + + + + ) +} +``` + +### Interactive result + + + {() => } + diff --git a/sidebars.js b/sidebars.js index b530fb3..8ff77d4 100644 --- a/sidebars.js +++ b/sidebars.js @@ -1,6 +1,7 @@ module.exports = { someSidebar: { Introduction: ["motivation", "quick-start", "features"], + Recipes: ["recipes/invalidate-query"], "API Reference": [ { type: "category",