Skip to content

Commit f015035

Browse files
committed
fix(core): useSignal docs, useAsync type
1 parent 794c1b9 commit f015035

File tree

14 files changed

+282
-188
lines changed

14 files changed

+282
-188
lines changed

packages/docs/src/routes/api/qwik/api.json

Lines changed: 8 additions & 22 deletions
Large diffs are not rendered by default.

packages/docs/src/routes/api/qwik/index.mdx

Lines changed: 91 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -128,17 +128,6 @@ export type AsyncFn<T> = (ctx: AsyncCtx) => Promise<T>;
128128

129129
[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-async.ts)
130130

131-
## AsyncReturnType
132-
133-
```typescript
134-
export type AsyncReturnType<T> =
135-
T extends Promise<infer T> ? AsyncSignal<T> : AsyncSignal<T>;
136-
```
137-
138-
**References:** [AsyncSignal](#asyncsignal)
139-
140-
[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-async.ts)
141-
142131
## AsyncSignal
143132

144133
```typescript
@@ -172,7 +161,7 @@ Description
172161
173162
</td><td>
174163
175-
Error \| null
164+
Error \| undefined
176165
177166
</td><td>
178167
@@ -331,11 +320,11 @@ export interface CounterProps {
331320
step?: number;
332321
}
333322
export const Counter = component$((props: CounterProps) => {
334-
const state = useStore({ count: props.initialValue || 0 });
323+
const state = useSignal(props.initialValue || 0);
335324
return (
336325
<div>
337-
<span>{state.count}</span>
338-
<button onClick$={() => (state.count += props.step || 1)}>+</button>
326+
<span>{state.value}</span>
327+
<button onClick$={() => (state.value += props.step || 1)}>+</button>
339328
</div>
340329
);
341330
});
@@ -836,7 +825,7 @@ The QRL must be a function which returns the value of the signal. The function m
836825
837826
```typescript
838827
createAsync$: <T>(qrl: () => Promise<T>, options?: ComputedOptions) =>
839-
AsyncReturnType<T>;
828+
AsyncSignal<T>;
840829
```
841830
842831
<table><thead><tr><th>
@@ -880,7 +869,7 @@ _(Optional)_
880869
881870
**Returns:**
882871
883-
[AsyncReturnType](#asyncreturntype)&lt;T&gt;
872+
[AsyncSignal](#asyncsignal)&lt;T&gt;
884873
885874
[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/reactive-primitives/signal.public.ts)
886875
@@ -8878,6 +8867,8 @@ const Cmp = component$(() => {
88788867
useTask$(({ track }) => {
88798868
// Any signals or stores accessed inside the task will be tracked
88808869
const count = track(() => store.count);
8870+
// For stores you can also pass the store and specify the property
8871+
track(store, "count");
88818872
// You can also pass a signal to track() directly
88828873
const signalCount = track(signal);
88838874
store.doubleCount = count + signalCount;
@@ -9010,9 +9001,7 @@ T
90109001
90119002
## useAsync$
90129003
9013-
Creates an AsyncSignal which is calculated from the given async function. If the function uses reactive state, and that state changes, the AsyncSignal is recalculated, and if the result changed, all tasks which are tracking the AsyncSignal will be re-run and all components that read the AsyncSignal will be re-rendered.
9014-
9015-
The function must not have any side effects, as it can run multiple times.
9004+
Creates an AsyncSignal which holds the result of the given async function. If the function uses `track()` to track reactive state, and that state changes, the AsyncSignal is recalculated, and if the result changed, all tasks which are tracking the AsyncSignal will be re-run and all subscribers (components, tasks etc) that read the AsyncSignal will be updated.
90169005
90179006
If the async function throws an error, the AsyncSignal will capture the error and set the `error` property. The error can be cleared by re-running the async function successfully.
90189007
@@ -9024,7 +9013,7 @@ If the value has been resolved, but the async function is re-running, reading th
90249013
90259014
```typescript
90269015
useAsync$: <T>(qrl: AsyncFn<T>, options?: ComputedOptions | undefined) =>
9027-
AsyncReturnType<T>;
9016+
AsyncSignal<T>;
90289017
```
90299018
90309019
<table><thead><tr><th>
@@ -9068,7 +9057,7 @@ _(Optional)_
90689057
90699058
**Returns:**
90709059
9071-
[AsyncReturnType](#asyncreturntype)&lt;T&gt;
9060+
[AsyncSignal](#asyncsignal)&lt;T&gt;
90729061
90739062
[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/use/use-async.ts)
90749063
@@ -9706,6 +9695,43 @@ T \| undefined
97069695
97079696
## useSignal
97089697
9698+
Creates an object with a single reactive `.value` property, that Qwik can track across serializations.
9699+
9700+
Use it to create state for your application. The object has a getter and setter to track reads and writes of the `.value` property. When the value changes, any functions that read from it will re-run.
9701+
9702+
Prefer `useSignal` over `useStore` when possible, as it is more efficient.
9703+
9704+
### Example
9705+
9706+
```tsx
9707+
const Signals = component$(() => {
9708+
const counter = useSignal(1);
9709+
const text = useSignal('changeme');
9710+
const toggle = useSignal(false);
9711+
9712+
// useSignal() can also accept a function to calculate the initial value
9713+
const state = useSignal(() => {
9714+
return expensiveInitialValue();
9715+
});
9716+
9717+
return (
9718+
<div>
9719+
<button onClick$={() => counter.value++}>Counter: {counter.value}</button>
9720+
{
9721+
// pass signal values as the value, the optimizer will make it pass the signal
9722+
}
9723+
<Child state={state.value} />
9724+
{
9725+
// signals can be bound to inputs. A property named `bind:x` implies that the property
9726+
is a signal
9727+
}
9728+
<input type="text" bind:value={text} />
9729+
<input type="checkbox" bind:checked={toggle} />
9730+
</div>
9731+
);
9732+
});
9733+
```
9734+
97099735
```typescript
97109736
useSignal: UseSignal;
97119737
```
@@ -9714,6 +9740,43 @@ useSignal: UseSignal;
97149740
97159741
## UseSignal
97169742
9743+
Creates an object with a single reactive `.value` property, that Qwik can track across serializations.
9744+
9745+
Use it to create state for your application. The object has a getter and setter to track reads and writes of the `.value` property. When the value changes, any functions that read from it will re-run.
9746+
9747+
Prefer `useSignal` over `useStore` when possible, as it is more efficient.
9748+
9749+
### Example
9750+
9751+
```tsx
9752+
const Signals = component$(() => {
9753+
const counter = useSignal(1);
9754+
const text = useSignal('changeme');
9755+
const toggle = useSignal(false);
9756+
9757+
// useSignal() can also accept a function to calculate the initial value
9758+
const state = useSignal(() => {
9759+
return expensiveInitialValue();
9760+
});
9761+
9762+
return (
9763+
<div>
9764+
<button onClick$={() => counter.value++}>Counter: {counter.value}</button>
9765+
{
9766+
// pass signal values as the value, the optimizer will make it pass the signal
9767+
}
9768+
<Child state={state.value} />
9769+
{
9770+
// signals can be bound to inputs. A property named `bind:x` implies that the property
9771+
is a signal
9772+
}
9773+
<input type="text" bind:value={text} />
9774+
<input type="checkbox" bind:checked={toggle} />
9775+
</div>
9776+
);
9777+
});
9778+
```
9779+
97179780
```typescript
97189781
useSignal: UseSignal;
97199782
```
@@ -9722,9 +9785,13 @@ useSignal: UseSignal;
97229785
97239786
## useStore
97249787
9725-
Creates an object that Qwik can track across serializations.
9788+
Creates a reactive object that Qwik can track across serialization.
9789+
9790+
Use it to create state for your application. The returned object is a Proxy that tracks reads and writes. When any of the properties change, the functions that read those properties will re-run.
9791+
9792+
`Store`s are deep by default, meaning that any objects assigned to properties will also become `Store`s. This includes arrays.
97269793
9727-
Use `useStore` to create a state for your application. The returned object is a proxy that has a unique ID. The ID of the object is used in the `QRL`s to refer to the store.
9794+
Prefer `useSignal` over `useStore` when possible, as it is more efficient.
97289795
97299796
### Example
97309797

packages/qwik/src/core/examples.tsx

Lines changed: 44 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import { useStyles$, useStylesScoped$ } from './use/use-styles';
1515
import { useTask$ } from './use/use-task-dollar';
1616
import { useVisibleTask$ } from './use/use-visible-task-dollar';
1717
import { implicit$FirstArg } from './shared/qrl/implicit_dollar';
18-
import { isServer, isBrowser } from '../build';
1918

2019
//////////////////////////////////////////////////////////
2120
//////////////////////////////////////////////////////////
@@ -30,11 +29,11 @@ export interface CounterProps {
3029
step?: number;
3130
}
3231
export const Counter = component$((props: CounterProps) => {
33-
const state = useStore({ count: props.initialValue || 0 });
32+
const state = useSignal(props.initialValue || 0);
3433
return (
3534
<div>
36-
<span>{state.count}</span>
37-
<button onClick$={() => (state.count += props.step || 1)}>+</button>
35+
<span>{state.value}</span>
36+
<button onClick$={() => (state.value += props.step || 1)}>+</button>
3837
</div>
3938
);
4039
});
@@ -215,6 +214,8 @@ export const CmpInline = component$(() => {
215214
useTask$(({ track }) => {
216215
// Any signals or stores accessed inside the task will be tracked
217216
const count = track(() => store.count);
217+
// For stores you can also pass the store and specify the property
218+
track(store, 'count');
218219
// You can also pass a signal to track() directly
219220
const signalCount = track(signal);
220221
store.doubleCount = count + signalCount;
@@ -240,102 +241,6 @@ export const CmpInline = component$(() => {
240241
return Cmp;
241242
};
242243

243-
() => {
244-
let db: any;
245-
// <docs anchor="use-server-mount">
246-
const Cmp = component$(() => {
247-
const store = useStore({
248-
users: [],
249-
});
250-
251-
useTask$(async () => {
252-
if (isServer) {
253-
// This code will ONLY run once in the server, when the component is mounted
254-
store.users = await db.requestUsers();
255-
}
256-
});
257-
258-
return (
259-
<div>
260-
{store.users.map((user) => (
261-
<User user={user} />
262-
))}
263-
</div>
264-
);
265-
});
266-
267-
interface User {
268-
name: string;
269-
}
270-
function User(props: { user: User }) {
271-
return <div>Name: {props.user.name}</div>;
272-
}
273-
// </docs>
274-
return Cmp;
275-
};
276-
277-
() => {
278-
// <docs anchor="use-client-mount">
279-
const Cmp = component$(() => {
280-
useTask$(async () => {
281-
if (isBrowser) {
282-
// This code will ONLY run once in the client, when the component is mounted
283-
}
284-
});
285-
286-
return <div>Cmp</div>;
287-
});
288-
// </docs>
289-
return Cmp;
290-
};
291-
292-
() => {
293-
// <docs anchor="use-mount">
294-
const Cmp = component$(() => {
295-
const store = useStore({
296-
temp: 0,
297-
});
298-
299-
useTask$(async () => {
300-
// This code will run once whenever a component is mounted in the server, or in the client
301-
const res = await fetch('weather-api.example');
302-
const json = (await res.json()) as any;
303-
store.temp = json.temp;
304-
});
305-
306-
return (
307-
<div>
308-
<p>The temperature is: ${store.temp}</p>
309-
</div>
310-
);
311-
});
312-
// </docs>
313-
return Cmp;
314-
};
315-
316-
() => {
317-
// <docs anchor="use-client-effect">
318-
const Timer = component$(() => {
319-
const store = useStore({
320-
count: 0,
321-
});
322-
323-
useVisibleTask$(() => {
324-
// Only runs in the client
325-
const timer = setInterval(() => {
326-
store.count++;
327-
}, 500);
328-
return () => {
329-
clearInterval(timer);
330-
};
331-
});
332-
333-
return <div>{store.count}</div>;
334-
});
335-
// </docs>
336-
return Timer;
337-
};
338-
339244
() => {
340245
// <docs anchor="use-store">
341246
const Stores = component$(() => {
@@ -394,6 +299,45 @@ export const CmpInline = component$(() => {
394299
return Stores;
395300
};
396301

302+
() => {
303+
// <docs anchor="use-signal">
304+
const Signals = component$(() => {
305+
const counter = useSignal(1);
306+
const text = useSignal('changeme');
307+
const toggle = useSignal(false);
308+
309+
// useSignal() can also accept a function to calculate the initial value
310+
const state = useSignal(() => {
311+
return expensiveInitialValue();
312+
});
313+
314+
return (
315+
<div>
316+
<button onClick$={() => counter.value++}>Counter: {counter.value}</button>
317+
{
318+
// pass signal values as the value, the optimizer will make it pass the signal
319+
}
320+
<Child state={state.value} />
321+
{
322+
// signals can be bound to inputs. A property named `bind:x` implies that the property is a signal
323+
}
324+
<input type="text" bind:value={text} />
325+
<input type="checkbox" bind:checked={toggle} />
326+
</div>
327+
);
328+
});
329+
// </docs>
330+
331+
function expensiveInitialValue() {
332+
return 42;
333+
}
334+
335+
function Child(_props: any) {
336+
return <div />;
337+
}
338+
return Signals;
339+
};
340+
397341
//
398342
// <docs anchor="context">
399343
// Declare the Context type.

packages/qwik/src/core/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ export { useTaskQrl } from './use/use-task';
159159
export { useTask$ } from './use/use-task-dollar';
160160
export { useVisibleTask$ } from './use/use-visible-task-dollar';
161161
export { useComputed$ } from './use/use-computed';
162-
export type { AsyncFn, AsyncReturnType } from './use/use-async';
162+
export type { AsyncFn } from './use/use-async';
163163
export { useAsyncQrl, useAsync$ } from './use/use-async';
164164
export { useErrorBoundary } from './use/use-error-boundary';
165165
export type { ErrorBoundaryStore } from './shared/error/error-handling';

0 commit comments

Comments
 (0)