diff --git a/examples/react/query-network-status/.gitignore b/examples/react/query-network-status/.gitignore new file mode 100644 index 0000000..0c4423e --- /dev/null +++ b/examples/react/query-network-status/.gitignore @@ -0,0 +1,29 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# Lock files +package-lock.json +pnpm-lock.yaml +yarn.lock diff --git a/examples/react/query-network-status/README.md b/examples/react/query-network-status/README.md new file mode 100644 index 0000000..1cf8892 --- /dev/null +++ b/examples/react/query-network-status/README.md @@ -0,0 +1,6 @@ +# Example + +To run this example: + +- `npm install` +- `npm run dev` diff --git a/examples/react/query-network-status/index.html b/examples/react/query-network-status/index.html new file mode 100644 index 0000000..cf7fb58 --- /dev/null +++ b/examples/react/query-network-status/index.html @@ -0,0 +1,13 @@ + + + + + + + Floppy Disk - Query & Network Status + + +
+ + + diff --git a/examples/react/query-network-status/index.jsx b/examples/react/query-network-status/index.jsx new file mode 100644 index 0000000..ded5159 --- /dev/null +++ b/examples/react/query-network-status/index.jsx @@ -0,0 +1,84 @@ +import React, { useState } from 'react'; +import ReactDOM from 'react-dom/client'; + +import { createQuery } from 'floppy-disk'; + +const usePsyduckQuery = createQuery( + async () => { + const res = await fetch('https://pokeapi.co/api/v2/pokemon/psyduck'); + if (res.ok) return res.json(); + throw res; + }, + { + defaultDeps: (state) => [state.data, state.error, state.isWaiting], + onBeforeFetch: (cancel) => { + if (!navigator.onLine) cancel(); + }, + }, +); + +const useEeveeQuery = createQuery( + async () => { + const res = await fetch('https://pokeapi.co/api/v2/pokemon/eevee-x'); // Expected wrong URL, to simulate error + if (res.ok) return res.json(); + throw res; + }, + { + defaultDeps: (state) => [state.data, state.error, state.isWaiting], + retry: () => { + if (navigator.onLine) return 2; + return 0; + }, + }, +); + +function App() { + const [showQuery1, setShowQuery1] = useState(false); + const [showQuery2, setShowQuery2] = useState(false); + + return ( +
+

💾 Floppy Disk - Query & Network Status

+ +
+

Example 1: Disable fetch when offline

+ + {showQuery1 && } + +
+

Example 2: Disable retries when offline

+ + {showQuery2 && } +
+ ); +} + +function Query1() { + const { data = {}, isWaiting } = usePsyduckQuery(); + return ( +
+ + {isWaiting &&
Fetching data... ⏳
} +
+ ); +} + +function Query2() { + const { data = {}, isWaiting } = useEeveeQuery(); + return ( +
+ + {isWaiting &&
Fetching data... ⏳
} +
+ ); +} + +ReactDOM.createRoot(document.getElementById('root')).render(); diff --git a/examples/react/query-network-status/package.json b/examples/react/query-network-status/package.json new file mode 100644 index 0000000..fd0b15d --- /dev/null +++ b/examples/react/query-network-status/package.json @@ -0,0 +1,22 @@ +{ + "name": "floppy-disk-example", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "floppy-disk": "^2.6.0", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/react": "^18.2.15", + "@types/react-dom": "^18.2.7", + "@vitejs/plugin-react": "^4.0.3", + "vite": "^4.4.5" + } +} diff --git a/examples/react/suspense/.gitignore b/examples/react/suspense/.gitignore new file mode 100644 index 0000000..8f322f0 --- /dev/null +++ b/examples/react/suspense/.gitignore @@ -0,0 +1,35 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/examples/react/suspense/README.md b/examples/react/suspense/README.md new file mode 100644 index 0000000..0dc9ea2 --- /dev/null +++ b/examples/react/suspense/README.md @@ -0,0 +1,36 @@ +This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/examples/react/suspense/app/layout.js b/examples/react/suspense/app/layout.js new file mode 100644 index 0000000..cd29ec9 --- /dev/null +++ b/examples/react/suspense/app/layout.js @@ -0,0 +1,11 @@ +export const metadata = { + title: 'Dependent Queries | Floppy Disk', +}; + +export default function RootLayout({ children }) { + return ( + + {children} + + ); +} diff --git a/examples/react/suspense/app/page.js b/examples/react/suspense/app/page.js new file mode 100644 index 0000000..aebb1a0 --- /dev/null +++ b/examples/react/suspense/app/page.js @@ -0,0 +1,63 @@ +'use client'; + +import { Suspense, useEffect, useState } from 'react'; + +import { createQuery } from 'floppy-disk'; + +const usePokemonQuery = createQuery( + async ({ pokemonName }) => { + const res = await fetch(`https://pokeapi.co/api/v2/pokemon/${pokemonName}`); + if (res.ok) return res.json(); + throw res; + }, + { + enabled: ({ pokemonName }) => !!pokemonName, + onBeforeFetch: (_, state) => { + console.info(state); + }, + }, +); + +export default function App() { + const [pokemonName, setPokemonName] = useState(); + + return ( +
+

💾 Floppy Disk - Suspense

+ + Loading... ⏳}> + + + +
+ +
+ + + +
+ + {pokemonName ? ( + Loading... ⏳}> + + + ) : ( +

Select a pokemon...

+ )} +
+ ); +} + +function PokemonDetail({ pokemonName }) { + const { data } = usePokemonQuery.suspend({ pokemonName }); + return ( + <> +

{data.name}

+ + + ); +} diff --git a/examples/react/suspense/next.config.js b/examples/react/suspense/next.config.js new file mode 100644 index 0000000..767719f --- /dev/null +++ b/examples/react/suspense/next.config.js @@ -0,0 +1,4 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = {} + +module.exports = nextConfig diff --git a/examples/react/suspense/package.json b/examples/react/suspense/package.json new file mode 100644 index 0000000..73e5fd8 --- /dev/null +++ b/examples/react/suspense/package.json @@ -0,0 +1,17 @@ +{ + "name": "floppy-disk-example", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "floppy-disk": "^2.6.0", + "next": "13.5.2", + "react": "18.2.0", + "react-dom": "18.2.0" + } +}