Skip to content

Commit

Permalink
feat(solid-query): Solid Query Adapter for TanStack Query (TanStack#4211
Browse files Browse the repository at this point in the history
)

* feat(solid-query): Solid Query Adapter for TanStack Query

RELEASE_ALL

Add an adapter to TanStack Query to support SolidJS.

Co-authored-by: Aryan Deora <[email protected]>
Co-authored-by: Jen Kaplan <[email protected]>

* Fixed Tests and included changes from feedback

* Prettier Format Code

Collaborators:

@oscartbeaumont
@lukesmurray
@jennyckaplan

* Readme Update

Collaborators:

@oscartbeaumont
@lukesmurray
@jennyckaplan

Co-Authored-By: Oscar Beaumont <[email protected]>
Co-Authored-By: Luke Murray <[email protected]>
Co-Authored-By: Jen Kaplan <[email protected]>

* Fixing tsconfig for CI test runner

Co-Authored-By: Oscar Beaumont <[email protected]>
Co-Authored-By: Luke Murray <[email protected]>
Co-Authored-By: Jen Kaplan <[email protected]>

* (fix: ci) CI Test fix

Co-Authored-By: Oscar Beaumont <[email protected]>
Co-Authored-By: Luke Murray <[email protected]>
Co-Authored-By: Jen Kaplan <[email protected]>

* (fix: tests): Remove React 17 check

Co-Authored-By: Oscar Beaumont <[email protected]>
Co-Authored-By: Luke Murray <[email protected]>
Co-Authored-By: Jen Kaplan <[email protected]>

* Update packages/solid-query/src/__tests__/createQuery.test.tsx

* Locking vite-plugin-solid version

Co-Authored-By: Oscar Beaumont <[email protected]>
Co-Authored-By: Luke Murray <[email protected]>
Co-Authored-By: Jen Kaplan <[email protected]>

Co-authored-by: Aryan Deora <[email protected]>
Co-authored-by: Jen Kaplan <[email protected]>
Co-authored-by: Oscar Beaumont <[email protected]>
Co-authored-by: Jen Kaplan <[email protected]>
Co-authored-by: Dominik Dorfmeister <[email protected]>
  • Loading branch information
6 people authored Sep 24, 2022
1 parent b31827d commit fd68b22
Show file tree
Hide file tree
Showing 72 changed files with 17,190 additions and 3,026 deletions.
2 changes: 1 addition & 1 deletion .codesandbox/ci.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"installCommand": "install:csb",
"sandboxes": ["/examples/react/basic", "/examples/react/basic-typescript"],
"sandboxes": ["/examples/react/basic", "/examples/react/basic-typescript", "/examples/solid/basic-typescript"],
"packages": ["packages/**"],
"node": "16"
}
11 changes: 10 additions & 1 deletion babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ module.exports = {
},
],
'@babel/preset-typescript',
'@babel/react',
],
plugins: [
cjs && ['@babel/transform-modules-commonjs', { loose }],
Expand All @@ -32,4 +31,14 @@ module.exports = {
},
],
].filter(Boolean),
overrides: [
{
exclude: './packages/solid-query/**',
presets: ['@babel/react'],
},
{
include: './packages/solid-query/**',
presets: ['babel-preset-solid'],
},
],
}
201 changes: 198 additions & 3 deletions docs/adapters/solid-query.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,205 @@
---
title: Solid Query (Coming Soon)
title: Solid Query
---

The `@tanstack/solid-query` package provides a 1st-class API for using TanStack Query with SolidJS.

> ⚠️ This module has not yet been developed. It requires an adapter similar to `react-query` to work. We estimate the amount of code to do this is low-to-moderate, but does require familiarity with the SolidJS framework. If you would like to contribute this adapter, please open a PR!
## Example

The `@tanstack/solid-query` package offers a 1st-class API for using TanStack Query via Solid. However, all of the primitives you receive from this API are core APIs that are shared across all of the TanStack Adapters including the Query Client, query results, query subscriptions, etc.
```tsx
import { QueryClient, QueryClientProvider, createQuery } from '@tanstack/solid-query'
import { Switch, Match, For } from 'solid-js'

const queryClient = new QueryClient()

function Example() {
const query = createQuery(() => ['todos'], fetchTodos)

return (
<div>
<Switch>
<Match when={query.isLoading}>
<p>Loading...</p>
</Match>
<Match when={query.isError}>
<p>Error: {query.error.message}</p>
</Match>
<Match when={query.isSuccess}>
<For each={query.data}>
{(todo) => <p>{todo.title}</p>}
</For>
</Match>
</Switch>
</div>
)
}

function App() {
return (
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
)
}

```

## Available Functions

Solid Query offers useful primitives and functions that will make managing server state in SolidJS apps easier.

- `createQuery`
- `createQueries`
- `createInfiniteQueries`
- `createMutation`
- `useIsFetching`
- `useIsMutating`
- `useQueryClient`
- `QueryClient`
- `QueryClientProvider`




## Important Differences between Solid Query & React Query

Solid Query offers an API similar to React Query, but there are some key differences to be mindful of.

- To maintain their reactivity, Query keys need to be wrapped inside a function while using `createQuery`, `createQueries`, `createInfiniteQuery` and `useIsFetching`.

```tsx
// ❌ react version
useQuery(["todos", todo], fetchTodos)

// ✅ solid version
createQuery(() => ["todos", todo()], fetchTodos)
```

- Suspense works for queries out of the box if you access the query data inside a `<Suspense>` boundary.

```tsx
import { For, Suspense } from 'solid-js'

function Example() {
const query = createQuery(() => ['todos'], fetchTodos)
return (
<div>
{/* ✅ Will trigger loading fallback, data accessed in a suspense context. */}
<Suspense fallback={"Loading..."}>
<For each={query.data}>{(todo) => <div>{todo.title}</div>}</For>
</Suspense>
{/* ❌ Will not trigger loading fallback, data not accessed in a suspense context. */}
<For each={query.data}>{(todo) => <div>{todo.title}</div>}</For>
</div>
)
}
```

- Solid Query primitives (`createX`) do not support destructuring. The return value from these functions is a store, and their properties are only tracked in a reactive context.

```tsx
import { QueryClient, QueryClientProvider, createQuery } from '@tanstack/solid-query'
import { Match, Switch } from 'solid-js'

const queryClient = new QueryClient()

export default function App() {
return (
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
)
}

function Example() {
// ❌ react version -- supports destructing outside reactive context
// const { isLoading, error, data } = useQuery(['repoData'], () =>
// fetch('https://api.github.com/repos/tannerlinsley/react-query').then(res =>
// res.json()
// )
// )

// ✅ solid version -- does not support destructuring outside reactive context
const query = createQuery(
() => ['repoData'],
() =>
fetch('https://api.github.com/repos/tannerlinsley/react-query').then(
(res) => res.json(),
),
)

// ✅ access query properties in JSX reactive context
return (
<Switch>
<Match when={query.isLoading}>Loading...</Match>
<Match when={query.isError}>Error: {query.error.message}</Match>
<Match when={query.isSuccess}>
<div>
<h1>{query.data.name}</h1>
<p>{query.data.description}</p>
<strong>👀 {query.data.subscribers_count}</strong>{' '}
<strong>✨ {query.data.stargazers_count}</strong>{' '}
<strong>🍴 {query.data.forks_count}</strong>
</div>
</Match>
</Switch>
)
}
```

- If you want options to be reactive you need to pass them using object getter syntax. This may look strange at first but it leads to more idiomatic solid code.

```tsx
import {
QueryClient,
QueryClientProvider,
createQuery,
} from '@tanstack/solid-query'
import { createSignal, For } from 'solid-js'

const queryClient = new QueryClient()

function Example() {
const [enabled, setEnabled] = createSignal(false)
const query = createQuery(() => ['todos'], fetchTodos, {
// ❌ passing a signal directly is not reactive
// enabled: enabled(),

// ✅ passing a function that returns a signal is reactive
get enabled() {
return enabled()
},
})

return (
<div>
<Switch>
<Match when={query.isLoading}>
<p>Loading...</p>
</Match>
<Match when={query.isError}>
<p>Error: {query.error.message}</p>
</Match>
<Match when={query.isSuccess}>
<For each={query.data}>
{(todo) => <p>{todo.title}</p>}
</For>
</Match>
</Switch>
<button onClick={() => setEnabled(!enabled())}>Toggle enabled</button>
</div>
)
}

function App() {
return (
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
)
}
```

- Errors can be caught and reset using SolidJS' native `ErrorBoundary` component. `QueryErrorResetBoundary` is not needed with Solid Query

- Since Property tracking is handled through Solid's fine grained reactivity, options like `notifyOnChangeProps` are not needed
22 changes: 22 additions & 0 deletions examples/solid/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Examples to Add

- auto-refetching 🚫 nextjs (react only)
- basic 🚫 javascript (only converting typescript)
- basic-graphql-request 🟢
- basic-typescript 🟢
- custom-hooks 🚫 not implemented in react
- default-query-function 🟡 (green styling for cached post not working)
- focus-refetching 🚫 not implemented in react
- load-more-infinite-scroll 🚫 nextjs (react only)
- nextjs 🚫 nextjs (react only)
- offline 🔴
- optimistic-updates 🚫 not implemented in react
- optimistic-updates-typescript 🚫 nextjs (react only)
- pagination 🚫 nextjs (react only)
- playground 🔴
- prefetching 🚫 nextjs (react only)
- react-native 🚫 react native (react only)
- rick-morty 🔴
- simple 🟢
- star-wars 🔴
- suspense 🔴
10 changes: 10 additions & 0 deletions examples/solid/basic-graphql-request/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"parserOptions": {
"project": "./tsconfig.json",
"sourceType": "module"
},
"rules": {
"react/react-in-jsx-scope": "off",
"jsx-a11y/anchor-is-valid": "off"
}
}
4 changes: 4 additions & 0 deletions examples/solid/basic-graphql-request/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
dist
.yalc
yalc.lock
6 changes: 6 additions & 0 deletions examples/solid/basic-graphql-request/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Example

To run this example:

- `npm install`
- `npm run start`
16 changes: 16 additions & 0 deletions examples/solid/basic-graphql-request/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="shortcut icon" type="image/ico" href="/src/assets/favicon.ico" />
<title>Solid App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>

<script src="/src/index.tsx" type="module"></script>
</body>
</html>
24 changes: 24 additions & 0 deletions examples/solid/basic-graphql-request/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@tanstack/query-example-solid-basic-graphql-request",
"private": true,
"version": "0.0.0",
"description": "",
"scripts": {
"start": "vite",
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
},
"license": "MIT",
"dependencies": {
"@tanstack/solid-query": "^4.3.9",
"graphql": "^16.6.0",
"graphql-request": "^5.0.0",
"solid-js": "^1.5.1"
},
"devDependencies": {
"typescript": "^4.8.2",
"vite": "^3.0.9",
"vite-plugin-solid": "2.3.6"
}
}
Binary file not shown.
Loading

0 comments on commit fd68b22

Please sign in to comment.