Skip to content

Commit a085a70

Browse files
authored
Merge pull request #20 from appwrite/feat-tanstack-start-starter
Feat: Tanstack Start support
2 parents cf5a5b2 + 1986114 commit a085a70

31 files changed

+11045
-0
lines changed

tanstack-start/starter/.cta.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"projectName": "starter",
3+
"mode": "file-router",
4+
"typescript": true,
5+
"tailwind": true,
6+
"packageManager": "npm",
7+
"addOnOptions": {},
8+
"git": true,
9+
"version": 1,
10+
"framework": "react-cra",
11+
"chosenAddOns": [
12+
"biome",
13+
"start"
14+
]
15+
}

tanstack-start/starter/.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
node_modules
2+
.DS_Store
3+
dist
4+
dist-ssr
5+
*.local
6+
count.txt
7+
.env
8+
.nitro
9+
.tanstack
10+
.output
11+
.vinxi
12+
todos.json
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"files.watcherExclude": {
3+
"**/routeTree.gen.ts": true
4+
},
5+
"search.exclude": {
6+
"**/routeTree.gen.ts": true
7+
},
8+
"files.readonlyInclude": {
9+
"**/routeTree.gen.ts": true
10+
},
11+
"[javascript]": {
12+
"editor.defaultFormatter": "biomejs.biome"
13+
},
14+
"[javascriptreact]": {
15+
"editor.defaultFormatter": "biomejs.biome"
16+
},
17+
"[typescript]": {
18+
"editor.defaultFormatter": "biomejs.biome"
19+
},
20+
"[typescriptreact]": {
21+
"editor.defaultFormatter": "biomejs.biome"
22+
},
23+
"[json]": {
24+
"editor.defaultFormatter": "biomejs.biome"
25+
},
26+
"[jsonc]": {
27+
"editor.defaultFormatter": "biomejs.biome"
28+
},
29+
"[css]": {
30+
"editor.defaultFormatter": "biomejs.biome"
31+
},
32+
"editor.codeActionsOnSave": {
33+
"source.organizeImports.biome": "explicit"
34+
}
35+
}

tanstack-start/starter/README.md

Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
Welcome to your new TanStack app!
2+
3+
# Getting Started
4+
5+
To run this application:
6+
7+
```bash
8+
npm install
9+
npm run start
10+
```
11+
12+
# Building For Production
13+
14+
To build this application for production:
15+
16+
```bash
17+
npm run build
18+
```
19+
20+
## Testing
21+
22+
This project uses [Vitest](https://vitest.dev/) for testing. You can run the tests with:
23+
24+
```bash
25+
npm run test
26+
```
27+
28+
## Styling
29+
30+
This project uses [Tailwind CSS](https://tailwindcss.com/) for styling.
31+
32+
33+
## Linting & Formatting
34+
35+
This project uses [Biome](https://biomejs.dev/) for linting and formatting. The following scripts are available:
36+
37+
38+
```bash
39+
npm run lint
40+
npm run format
41+
npm run check
42+
```
43+
44+
45+
46+
## Routing
47+
This project uses [TanStack Router](https://tanstack.com/router). The initial setup is a file based router. Which means that the routes are managed as files in `src/routes`.
48+
49+
### Adding A Route
50+
51+
To add a new route to your application just add another a new file in the `./src/routes` directory.
52+
53+
TanStack will automatically generate the content of the route file for you.
54+
55+
Now that you have two routes you can use a `Link` component to navigate between them.
56+
57+
### Adding Links
58+
59+
To use SPA (Single Page Application) navigation you will need to import the `Link` component from `@tanstack/react-router`.
60+
61+
```tsx
62+
import { Link } from "@tanstack/react-router";
63+
```
64+
65+
Then anywhere in your JSX you can use it like so:
66+
67+
```tsx
68+
<Link to="/about">About</Link>
69+
```
70+
71+
This will create a link that will navigate to the `/about` route.
72+
73+
More information on the `Link` component can be found in the [Link documentation](https://tanstack.com/router/v1/docs/framework/react/api/router/linkComponent).
74+
75+
### Using A Layout
76+
77+
In the File Based Routing setup the layout is located in `src/routes/__root.tsx`. Anything you add to the root route will appear in all the routes. The route content will appear in the JSX where you use the `<Outlet />` component.
78+
79+
Here is an example layout that includes a header:
80+
81+
```tsx
82+
import { Outlet, createRootRoute } from '@tanstack/react-router'
83+
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
84+
85+
import { Link } from "@tanstack/react-router";
86+
87+
export const Route = createRootRoute({
88+
component: () => (
89+
<>
90+
<header>
91+
<nav>
92+
<Link to="/">Home</Link>
93+
<Link to="/about">About</Link>
94+
</nav>
95+
</header>
96+
<Outlet />
97+
<TanStackRouterDevtools />
98+
</>
99+
),
100+
})
101+
```
102+
103+
The `<TanStackRouterDevtools />` component is not required so you can remove it if you don't want it in your layout.
104+
105+
More information on layouts can be found in the [Layouts documentation](https://tanstack.com/router/latest/docs/framework/react/guide/routing-concepts#layouts).
106+
107+
108+
## Data Fetching
109+
110+
There are multiple ways to fetch data in your application. You can use TanStack Query to fetch data from a server. But you can also use the `loader` functionality built into TanStack Router to load the data for a route before it's rendered.
111+
112+
For example:
113+
114+
```tsx
115+
const peopleRoute = createRoute({
116+
getParentRoute: () => rootRoute,
117+
path: "/people",
118+
loader: async () => {
119+
const response = await fetch("https://swapi.dev/api/people");
120+
return response.json() as Promise<{
121+
results: {
122+
name: string;
123+
}[];
124+
}>;
125+
},
126+
component: () => {
127+
const data = peopleRoute.useLoaderData();
128+
return (
129+
<ul>
130+
{data.results.map((person) => (
131+
<li key={person.name}>{person.name}</li>
132+
))}
133+
</ul>
134+
);
135+
},
136+
});
137+
```
138+
139+
Loaders simplify your data fetching logic dramatically. Check out more information in the [Loader documentation](https://tanstack.com/router/latest/docs/framework/react/guide/data-loading#loader-parameters).
140+
141+
### React-Query
142+
143+
React-Query is an excellent addition or alternative to route loading and integrating it into you application is a breeze.
144+
145+
First add your dependencies:
146+
147+
```bash
148+
npm install @tanstack/react-query @tanstack/react-query-devtools
149+
```
150+
151+
Next we'll need to create a query client and provider. We recommend putting those in `main.tsx`.
152+
153+
```tsx
154+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
155+
156+
// ...
157+
158+
const queryClient = new QueryClient();
159+
160+
// ...
161+
162+
if (!rootElement.innerHTML) {
163+
const root = ReactDOM.createRoot(rootElement);
164+
165+
root.render(
166+
<QueryClientProvider client={queryClient}>
167+
<RouterProvider router={router} />
168+
</QueryClientProvider>
169+
);
170+
}
171+
```
172+
173+
You can also add TanStack Query Devtools to the root route (optional).
174+
175+
```tsx
176+
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
177+
178+
const rootRoute = createRootRoute({
179+
component: () => (
180+
<>
181+
<Outlet />
182+
<ReactQueryDevtools buttonPosition="top-right" />
183+
<TanStackRouterDevtools />
184+
</>
185+
),
186+
});
187+
```
188+
189+
Now you can use `useQuery` to fetch your data.
190+
191+
```tsx
192+
import { useQuery } from "@tanstack/react-query";
193+
194+
import "./App.css";
195+
196+
function App() {
197+
const { data } = useQuery({
198+
queryKey: ["people"],
199+
queryFn: () =>
200+
fetch("https://swapi.dev/api/people")
201+
.then((res) => res.json())
202+
.then((data) => data.results as { name: string }[]),
203+
initialData: [],
204+
});
205+
206+
return (
207+
<div>
208+
<ul>
209+
{data.map((person) => (
210+
<li key={person.name}>{person.name}</li>
211+
))}
212+
</ul>
213+
</div>
214+
);
215+
}
216+
217+
export default App;
218+
```
219+
220+
You can find out everything you need to know on how to use React-Query in the [React-Query documentation](https://tanstack.com/query/latest/docs/framework/react/overview).
221+
222+
## State Management
223+
224+
Another common requirement for React applications is state management. There are many options for state management in React. TanStack Store provides a great starting point for your project.
225+
226+
First you need to add TanStack Store as a dependency:
227+
228+
```bash
229+
npm install @tanstack/store
230+
```
231+
232+
Now let's create a simple counter in the `src/App.tsx` file as a demonstration.
233+
234+
```tsx
235+
import { useStore } from "@tanstack/react-store";
236+
import { Store } from "@tanstack/store";
237+
import "./App.css";
238+
239+
const countStore = new Store(0);
240+
241+
function App() {
242+
const count = useStore(countStore);
243+
return (
244+
<div>
245+
<button onClick={() => countStore.setState((n) => n + 1)}>
246+
Increment - {count}
247+
</button>
248+
</div>
249+
);
250+
}
251+
252+
export default App;
253+
```
254+
255+
One of the many nice features of TanStack Store is the ability to derive state from other state. That derived state will update when the base state updates.
256+
257+
Let's check this out by doubling the count using derived state.
258+
259+
```tsx
260+
import { useStore } from "@tanstack/react-store";
261+
import { Store, Derived } from "@tanstack/store";
262+
import "./App.css";
263+
264+
const countStore = new Store(0);
265+
266+
const doubledStore = new Derived({
267+
fn: () => countStore.state * 2,
268+
deps: [countStore],
269+
});
270+
doubledStore.mount();
271+
272+
function App() {
273+
const count = useStore(countStore);
274+
const doubledCount = useStore(doubledStore);
275+
276+
return (
277+
<div>
278+
<button onClick={() => countStore.setState((n) => n + 1)}>
279+
Increment - {count}
280+
</button>
281+
<div>Doubled - {doubledCount}</div>
282+
</div>
283+
);
284+
}
285+
286+
export default App;
287+
```
288+
289+
We use the `Derived` class to create a new store that is derived from another store. The `Derived` class has a `mount` method that will start the derived store updating.
290+
291+
Once we've created the derived store we can use it in the `App` component just like we would any other store using the `useStore` hook.
292+
293+
You can find out everything you need to know on how to use TanStack Store in the [TanStack Store documentation](https://tanstack.com/store/latest).
294+
295+
# Demo files
296+
297+
Files prefixed with `demo` can be safely deleted. They are there to provide a starting point for you to play around with the features you've installed.
298+
299+
# Learn More
300+
301+
You can learn more about all of the offerings from TanStack in the [TanStack documentation](https://tanstack.com).

0 commit comments

Comments
 (0)