@riktajs/react 0.11.5 → 0.11.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,13 @@
1
1
  # @riktajs/react
2
2
 
3
- React utilities for Rikta SSR framework. Provides hooks and components for routing, navigation, SSR data access, and server interactions.
3
+ React utilities for Rikta SSR framework. Provides hooks for SSR data access, navigation, and server interactions using **native browser APIs**.
4
+
5
+ ## Philosophy
6
+
7
+ This package embraces the web platform by using native browser APIs for navigation:
8
+ - Use standard `<a href="...">` tags for links
9
+ - Use `useNavigate()` for programmatic navigation (uses `window.location` under the hood)
10
+ - Full page loads ensure SSR data is always fresh
4
11
 
5
12
  ## Installation
6
13
 
@@ -30,37 +37,56 @@ hydrateRoot(
30
37
  );
31
38
  ```
32
39
 
33
- ## Components
40
+ ## Navigation
34
41
 
35
- ### `<Link>`
42
+ ### Using Native Links
36
43
 
37
- Client-side navigation link component that uses the History API instead of full page reloads.
44
+ Use standard HTML anchor tags for navigation:
38
45
 
39
46
  ```tsx
40
- import { Link } from '@riktajs/react';
41
-
42
47
  function Navigation() {
43
48
  return (
44
49
  <nav>
45
- <Link href="/">Home</Link>
46
- <Link href="/about">About</Link>
47
- <Link href="/items/123">Item 123</Link>
48
-
49
- {/* With options */}
50
- <Link href="/dashboard" replace scroll={false}>
51
- Dashboard
52
- </Link>
50
+ <a href="/">Home</a>
51
+ <a href="/about">About</a>
52
+ <a href="/items/123">Item 123</a>
53
53
  </nav>
54
54
  );
55
55
  }
56
56
  ```
57
57
 
58
- **Props:**
59
- - `href` (required): Target URL
60
- - `replace`: Replace history entry instead of push
61
- - `scroll`: Scroll to top after navigation (default: `true`)
62
- - `state`: Additional state to pass to navigation
63
- - All standard `<a>` props are supported
58
+ ### Programmatic Navigation with `useNavigate()`
59
+
60
+ For programmatic navigation, use the `useNavigate()` hook:
61
+
62
+ ```tsx
63
+ import { useNavigate } from '@riktajs/react';
64
+
65
+ function MyComponent() {
66
+ const navigate = useNavigate();
67
+
68
+ const handleSubmit = async () => {
69
+ await saveData();
70
+ // Simple navigation
71
+ navigate('/success');
72
+ };
73
+
74
+ const handleSearch = (query: string) => {
75
+ // Navigation with query params - easy!
76
+ navigate('/search', { q: query, page: 1 });
77
+ // Results in: /search?q=query&page=1
78
+ };
79
+
80
+ const handleLogin = () => {
81
+ // Replace history entry (for redirects)
82
+ navigate('/dashboard', { replace: true });
83
+ };
84
+
85
+ return <button onClick={handleSubmit}>Submit</button>;
86
+ }
87
+ ```
88
+
89
+ ## Components
64
90
 
65
91
  ### `<RiktaProvider>`
66
92
 
@@ -80,27 +106,28 @@ function App() {
80
106
 
81
107
  ## Hooks
82
108
 
83
- ### `useNavigation()`
109
+ ### `useNavigate()`
84
110
 
85
- Programmatic navigation hook.
111
+ Programmatic navigation hook using native browser APIs.
86
112
 
87
113
  ```tsx
88
- import { useNavigation } from '@riktajs/react';
114
+ import { useNavigate } from '@riktajs/react';
89
115
 
90
116
  function MyComponent() {
91
- const { navigate, pathname } = useNavigation();
117
+ const navigate = useNavigate();
92
118
 
93
- const handleSubmit = async () => {
94
- await saveData();
95
- navigate('/success');
96
- };
119
+ // Simple navigation
120
+ navigate('/dashboard');
97
121
 
98
- // With options
122
+ // With query params
123
+ navigate('/search', { q: 'hello', page: 1 });
124
+ // Results in: /search?q=hello&page=1
125
+
126
+ // Replace history (no back button)
99
127
  navigate('/login', { replace: true });
100
- navigate('/next', { scroll: false });
101
- navigate('/edit', { state: { from: 'list' } });
102
128
 
103
- return <button onClick={handleSubmit}>Submit</button>;
129
+ // Params + options
130
+ navigate('/items', { filter: 'active' }, { replace: true });
104
131
  }
105
132
  ```
106
133
 
@@ -139,7 +166,7 @@ function SearchPage() {
139
166
  const page = parseInt(searchParams.get('page') ?? '1', 10);
140
167
 
141
168
  const handleSearch = (newQuery: string) => {
142
- setSearchParams({ q: newQuery, page: '1' });
169
+ setSearchParams({ q: newQuery, page: 1 });
143
170
  };
144
171
 
145
172
  return (
@@ -153,7 +180,7 @@ function SearchPage() {
153
180
 
154
181
  ### `useLocation()`
155
182
 
156
- Get current location information.
183
+ Access current location information directly from `window.location`.
157
184
 
158
185
  ```tsx
159
186
  import { useLocation } from '@riktajs/react';
@@ -172,34 +199,28 @@ function Breadcrumbs() {
172
199
 
173
200
  ### `useSsrData()`
174
201
 
175
- Access SSR data passed from server via `window.__SSR_DATA__`. The data structure includes:
176
- - `data`: The actual page data from the controller
177
- - `url`: The current URL
178
- - `title`: Page title (from `@Ssr` decorator)
179
- - `description`: Page description (from `@Ssr` decorator)
202
+ Access SSR data passed from the server via `window.__SSR_DATA__`.
180
203
 
181
204
  ```tsx
182
205
  import { useSsrData } from '@riktajs/react';
183
206
 
184
207
  interface PageData {
185
- page: string;
208
+ title: string;
186
209
  items: Array<{ id: string; name: string }>;
187
210
  }
188
211
 
189
212
  function ItemList() {
190
213
  const ssrData = useSsrData<PageData>();
191
214
 
192
- if (!ssrData) return <div>Loading...</div>;
193
-
194
- // Access page data
195
- const { data, title, url } = ssrData;
215
+ if (!ssrData) {
216
+ return <div>Loading...</div>;
217
+ }
196
218
 
197
219
  return (
198
220
  <div>
199
- <h1>{title ?? data.page}</h1>
200
- <p>Current URL: {url}</p>
221
+ <h1>{ssrData.data.title}</h1>
201
222
  <ul>
202
- {data.items.map(item => (
223
+ {ssrData.data.items.map(item => (
203
224
  <li key={item.id}>{item.name}</li>
204
225
  ))}
205
226
  </ul>
@@ -208,34 +229,9 @@ function ItemList() {
208
229
  }
209
230
  ```
210
231
 
211
- ### Client-Side Navigation with SSR Data Fetching
212
-
213
- When navigating client-side using `<Link>` or `navigate()`, `RiktaProvider` automatically fetches the SSR data for the new page from the server. This ensures:
214
-
215
- 1. **No page flash**: Data is fetched before the route changes
216
- 2. **Consistent data structure**: Same data shape as initial SSR
217
- 3. **SEO metadata**: Title and description are updated automatically
218
-
219
- ```tsx
220
- // App.tsx - Route based on ssrData.url for data consistency
221
- function App() {
222
- const ssrData = useSsrData<{ page: string }>();
223
-
224
- // Use ssrData.url for routing to ensure data and route are in sync
225
- const pathname = ssrData?.url?.split('?')[0] ?? '/';
226
-
227
- return (
228
- <Layout title={ssrData?.title}>
229
- {pathname === '/about' && <AboutPage />}
230
- {pathname === '/' && <HomePage />}
231
- </Layout>
232
- );
233
- }
234
- ```
235
-
236
232
  ### `useHydration()`
237
233
 
238
- Track hydration state for client-only rendering.
234
+ Track hydration state for handling SSR vs client rendering differences.
239
235
 
240
236
  ```tsx
241
237
  import { useHydration } from '@riktajs/react';
@@ -243,21 +239,14 @@ import { useHydration } from '@riktajs/react';
243
239
  function TimeDisplay() {
244
240
  const { isHydrated, isServer } = useHydration();
245
241
 
246
- // Avoid hydration mismatch with dynamic content
242
+ // On server and initial render, show static content
247
243
  if (!isHydrated) {
248
244
  return <span>Loading time...</span>;
249
245
  }
250
246
 
247
+ // After hydration, show dynamic content
251
248
  return <span>{new Date().toLocaleTimeString()}</span>;
252
249
  }
253
-
254
- function ClientOnlyComponent() {
255
- const { isHydrated } = useHydration();
256
-
257
- if (!isHydrated) return null;
258
-
259
- return <SomeClientOnlyLibrary />;
260
- }
261
250
  ```
262
251
 
263
252
  ### `useFetch()`
@@ -267,11 +256,6 @@ Data fetching hook with loading and error states.
267
256
  ```tsx
268
257
  import { useFetch } from '@riktajs/react';
269
258
 
270
- interface User {
271
- id: string;
272
- name: string;
273
- }
274
-
275
259
  function UserProfile({ userId }: { userId: string }) {
276
260
  const { data, loading, error, refetch } = useFetch<User>(
277
261
  `/api/users/${userId}`
@@ -288,40 +272,20 @@ function UserProfile({ userId }: { userId: string }) {
288
272
  </div>
289
273
  );
290
274
  }
291
-
292
- // With options
293
- const { data } = useFetch<Item[]>('/api/items', {
294
- headers: { 'Authorization': `Bearer ${token}` },
295
- deps: [token], // Refetch when token changes
296
- skip: !token, // Don't fetch until we have a token
297
- transform: (res) => res.results, // Transform response
298
- });
299
275
  ```
300
276
 
301
277
  ### `useAction()`
302
278
 
303
- Execute server actions (form submissions, mutations).
279
+ Execute server actions (mutations, form submissions).
304
280
 
305
281
  ```tsx
306
282
  import { useAction } from '@riktajs/react';
307
283
 
308
- interface CreateItemInput {
309
- name: string;
310
- price: number;
311
- }
312
-
313
- interface Item {
314
- id: string;
315
- name: string;
316
- price: number;
317
- }
318
-
319
284
  function CreateItemForm() {
320
285
  const { execute, pending, result } = useAction<CreateItemInput, Item>(
321
286
  '/api/items',
322
287
  {
323
288
  onSuccess: (item) => console.log('Created:', item),
324
- onError: (error) => console.error('Failed:', error),
325
289
  }
326
290
  );
327
291
 
@@ -345,54 +309,64 @@ function CreateItemForm() {
345
309
  </form>
346
310
  );
347
311
  }
348
-
349
- // DELETE action
350
- const { execute, pending } = useAction<{ id: string }, void>(
351
- '/api/items',
352
- { method: 'DELETE' }
353
- );
354
312
  ```
355
313
 
356
- ## TypeScript
314
+ ## TypeScript Support
357
315
 
358
- All exports are fully typed. Import types as needed:
316
+ All hooks and components are fully typed. Export types are available:
359
317
 
360
318
  ```tsx
361
319
  import type {
362
320
  SsrData,
363
- RouterContextValue,
364
- NavigateOptions,
365
321
  ActionResult,
366
322
  FetchState,
367
323
  ActionState,
368
- LinkProps,
324
+ RiktaProviderProps,
369
325
  HydrationState,
370
326
  Location,
327
+ NavigateFn,
328
+ NavigateOptions,
371
329
  } from '@riktajs/react';
372
330
  ```
373
331
 
374
- ## Integration with @riktajs/ssr
332
+ ## Migration from Previous Versions
375
333
 
376
- This package is designed to work seamlessly with `@riktajs/ssr`. The SSR plugin automatically injects `window.__SSR_DATA__` which `RiktaProvider` picks up.
334
+ If you were using the `<Link>` component or `useNavigation()`:
377
335
 
336
+ ### Before (v1.x)
378
337
  ```tsx
379
- // Server: page.controller.ts
380
- @Controller()
381
- export class PageController {
382
- @Get('/item/:id')
383
- @Render()
384
- getItem(@Param('id') id: string) {
385
- const item = getItemById(id);
386
- return { item, params: { id } };
387
- }
338
+ import { Link, useNavigation } from '@riktajs/react';
339
+
340
+ function Nav() {
341
+ const { navigate, pathname } = useNavigation();
342
+
343
+ return (
344
+ <nav>
345
+ <Link href="/about">About</Link>
346
+ <button onClick={() => navigate('/search', { state: { from: 'nav' } })}>
347
+ Search
348
+ </button>
349
+ </nav>
350
+ );
388
351
  }
352
+ ```
389
353
 
390
- // Client: ItemPage.tsx
391
- function ItemPage() {
392
- const ssrData = useSsrData<{ item: Item; params: { id: string } }>();
393
- const { id } = useParams();
354
+ ### After (v2.x)
355
+ ```tsx
356
+ import { useNavigate, useLocation } from '@riktajs/react';
357
+
358
+ function Nav() {
359
+ const navigate = useNavigate();
360
+ const { pathname } = useLocation();
394
361
 
395
- return <h1>{ssrData?.data.item.name} (ID: {id})</h1>;
362
+ return (
363
+ <nav>
364
+ <a href="/about">About</a>
365
+ <button onClick={() => navigate('/search', { q: '' })}>
366
+ Search
367
+ </button>
368
+ </nav>
369
+ );
396
370
  }
397
371
  ```
398
372