From 1a18f257c200cde302f02286ada3663087896b29 Mon Sep 17 00:00:00 2001 From: Jay Brass <92528213+Jemsco@users.noreply.github.com> Date: Wed, 1 May 2024 16:44:18 -0400 Subject: [PATCH 1/3] docs: Update components/tasks index.mdx verbiage and phrasing --- .../docs/(qwik)/components/tasks/index.mdx | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/packages/docs/src/routes/docs/(qwik)/components/tasks/index.mdx b/packages/docs/src/routes/docs/(qwik)/components/tasks/index.mdx index e1c01b5ec01..ce87601a2ab 100644 --- a/packages/docs/src/routes/docs/(qwik)/components/tasks/index.mdx +++ b/packages/docs/src/routes/docs/(qwik)/components/tasks/index.mdx @@ -18,6 +18,7 @@ contributors: - julianobrasil - adamdbradley - aendel + - jemsco updated_at: '2023-10-18T07:33:22Z' created_at: '2023-03-31T02:40:50Z' --- @@ -35,7 +36,7 @@ Tasks are meant for running asynchronous operations as part of component initial > - Task run on server and browser. > - Tasks run before rendering and can block rendering. -`useTask$()` should be your default go-to API for running asynchronous (or synchronous) work as part of component initialization or state change. It is only when you can't achieve what you need with `useTask$()` that you should consider using `useVisibleTask$()` or `useResource$()`. +`useTask$()` should be your default go-to API for running either synchronous or asynchronous work as part of component initialization or state change. It is only when you can't achieve what you need with `useTask$()` that you should consider using `useVisibleTask$()` or `useResource$()`. The basic use case for `useTask$()` is to perform work on component initialization. `useTask$()` has these properties: - It can run on either the server or in the browser. @@ -50,13 +51,13 @@ Sometimes a task should fetch data asynchronously and produce a signal (and not ## Lifecycle -Thanks to [Resumability](/docs/(qwik)/concepts/resumable/index.mdx), component lifetime and its lifecycle extend across server and browser runtime. Sometimes the component will first be rendered in the server, and other times it could be rendered in the browser. However, in both cases, the lifecycle (order) will be the same, only its execution location will be in different environments (server vs browser). +Thanks to [Resumability](/docs/(qwik)/concepts/resumable/index.mdx), the component's lifetime and lifecycle can extend across server and browser runtimes. This means the component might initially render on the server or directly in the browser. Regardless of where it is rendered, the lifecycle order remains the same, differing only in execution environment (server vs browser). -> **Note**: For systems that use hydration the execution of the application happens twice. Once on a server (SSR/SSG) and once on the browser (hydration). For this reason, many frameworks have "effects" which only execute on the browser. That means that the code that runs on the server is different than the code that runs on the browser. Qwik execution is unified, meaning if the code has already been executed on the server it does not re-execute it on the browser. +> **Note**: For systems that use hydration the execution of the application happens twice. Once on a server (SSR/SSG) and once on the browser (hydration). This is why many frameworks have "effects" which only execute on the browser. That means that the code that runs on the server is different than the code that runs on the browser. Qwik execution is unified, meaning if the code has already been executed on the server it does not re-execute it on the browser. **In Qwik, there are only 3 lifecycle stages:** -- `Task` - run before rendering and also when tracked state changes. (Tasks run sequentially, and block rendering.) +- `Task` - run before rendering and when tracked state changes. `Tasks` run sequentially, and block rendering. - `Render` - runs after `TASK` and before `VisibleTask` - `VisibleTask` - runs after `Render` and when the component becomes visible @@ -72,7 +73,7 @@ Thanks to [Resumability](/docs/(qwik)/concepts/resumable/index.mdx), component l > **Notice** that because the component was mounted in the server, **only useVisibleTask$() runs in the browser**. This is because the browser continues the same lifecycle, that was paused in the server right after the render and resumed in the browser. -**BROWSER**: Sometimes a component will be first mounted/rendered in the browser, for example when the user SPA navigates to a new page, or a "modal" component first appears in the page. In that case, the lifecycle will run like this: +**BROWSER**: When a component is first mounted or rendered in the browser, for example when a user navigates to a new page in a Single Page Application (SPA) or when a "modal" component initially appears on the page, the lifecycle will proceed as follows: ```bash useTask$ --> RENDER --> useVisibleTask$ @@ -107,7 +108,7 @@ Additionally, this task can be reactive and will re-execute when **tracked** [st > If `useTask$()` does not track any state, it will run **exactly once**, either in the server **or** in the browser (**not both**), depending where the component is initially rendered. Effectively behaving like an "on-mount" hook. -`useTask$()` will block the rendering of the component until after its async callback resolves, in other words, tasks execute sequentially even if they are asynchronous. (Only one task executes at a time / Tasks block rendering). +`useTask$()` will block the rendering of the component until after its async callback resolves, in other words, tasks execute sequentially even if they are asynchronous. (Only one task executes at a time). Let's look at the simplest use case of the task to run some asynchronous work on component initialization. @@ -142,20 +143,20 @@ const delay = (time: number) => new Promise((res) => setTimeout(res, time)); > - The `useTask$()` executes on the server as part of the SSR (the result may be cached in CDN.) > - Because the `useTask$()` blocks rendering, the rendered HTML page takes 4 seconds to render. > - Because this task has no `track()` it will never rerun, making it effectively an initialization code. -> - Because this component only renders on the server, the `useTask$()` will never run on the browser. (code will never download to browser.) +> - Because this component only renders on the server, the `useTask$()` will never be downloaded or run on the browser. -> Notice that `useTask$()` runs **BEFORE** the actual rendering and on the server. Therefore if you need to do DOM manipulation, use [`useVisibleTask$()`](#usevisibletask) instead, which runs on the browser after rendering. +> Notice that `useTask$()` runs on the server **BEFORE** the actual rendering. Therefore if you need to do DOM manipulation, use [`useVisibleTask$()`](#usevisibletask) instead, which runs on the browser after rendering. Use `useTask$()` when you need to: - Run async tasks before rendering - Run code only once before the component is first rendered - Programmatically run side-effect code when state changes -> Note, if you're thinking about loading data (like using `fetch()`) inside of `useTask$`, consider using [`useResource$()`](/docs/components/state/#useresource) instead. This API is more efficient in terms of leveraging SSR streaming and parallel data fetching. +> Note, if you're thinking about loading data using `fetch()` inside of `useTask$`, consider using [`useResource$()`](/docs/components/state/#useresource) instead. This API is more efficient in terms of leveraging SSR streaming and parallel data fetching. ### On mount -Qwik does not have a specific "on-mount" hook because useTask$() without track() effectively behaves like a mount hook. +Qwik does not have a specific "on-mount" hook because useTask$() without track() effectively behaves like an "on-mount" hook. This is because `useTask$` runs always at least once when the component is first mounted. @@ -173,11 +174,11 @@ export default component$(() => { }); ``` -One unique aspect of Qwik, is that components are mounted only ONCE across the server and client. This is a property of resumability. What it means, is that if `useTask$` runs during SSR it will not run again in the browser because Qwik does not hydrate. +One unique aspect of Qwik, is that components are mounted only **once** across the server and client. This is a property of resumability. What this means is that if `useTask$` is executed during Server-Side Rendering (SSR), it will not run again in the browser because Qwik does not perform hydration. ### `track()` -There are times when it is desirable to re-run a task when a component state changes. This is done by using the `track()` function. The `track()` function allows you to set up a dependency on a component state on the server (if initially rendered there) and then re-execute the task when the state changes _on the browser_ (the same task will never be executed twice on the server side). +There are times when it is desirable to re-run a task when a component state changes. This is done by using the `track()` function. The `track()` function allows you to set up a dependency on a component's state when initially rendered on the server, and then re-execute the task when the state changes in the browser. The same task will never be executed twice on the server. > **Note**: If all you want to do is compute a new state from an existing state synchronously, you should use [`useComputed$()`](/docs/components/state/#usecomputed) instead. @@ -215,16 +216,16 @@ const delay = (time: number) => new Promise((res) => setTimeout(res, time)); > On the server: > -> - The `useTask$()` runs on the server and the `track()` function sets up a subscription on `text` signal. +> - The `useTask$()` runs on the server and the `track()` function sets up a subscription on the `text` signal. > - The page is rendered. > > On the browser: -> - The `useTask$()` does not have to run (or be downloaded) eagerly because Qwik knows that the task is subscribed to the `text` signal from the server execution. +> - The `useTask$()` does not have to run or be downloaded eagerly because Qwik knows that the task is subscribed to the `text` signal from the server execution. > - When the user types in the input box, the `text` signal changes. Qwik knows that the `useTask$()` is subscribed to the `text` signal and it is at this time that the `useTask$()` closure is brought into the JavaScript VM to be executed. > > The `useTask$()` > -> - The `useTask$()` blocks rendering until it completes. If you don't want to block rendering (as in this case) make sure that the task is resolved, and run the delay work on a separate unconnected promise. (In our case we don't await `delay()`. Doing so would block rendering.) +> - The `useTask$()` blocks rendering until it completes. If you don't want to block rendering, make sure that the task is resolved, and run the delay work on a separate unconnected promise. In this example, we don't await `delay()` because it would block rendering. > Sometimes it is required to only run code either in the server or in the client. This can be achieved by using the `isServer` and `isBrowser` booleans exported from `@builder.io/qwik/build` as shown above. @@ -272,15 +273,15 @@ function delay(time: number) { ``` -> In this example the `track()` takes a function that not only reads the signal but also transforms its value to uppercase/lowercase. The `track()` is doing subscription on multiple signals and computes their value. +> In this example the `track()` takes a function that not only reads the signal but also transforms its value to uppercase/lowercase. The `track()` subscribes to multiple signals and computes their value. ### `cleanup()` -Sometimes when running a task cleanup work needs to be performed. When a new task is triggered, the previous task's `cleanup()` callback is invoked. (Also when the component is removed from the DOM then the `cleanup()` callback is also invoked.) +Sometimes when running a task, cleanup work needs to be performed. When a new task is triggered, the previous task's `cleanup()` callback is invoked. This callback is also invoked when the component is removed from the DOM. > - The `cleanup()` function is not invoked when the task is completed. It is only invoked when a new task is triggered or when the component is removed. > - The `cleanup()` function is invoked on the server after the applications are serialized into HTML. -> - The `cleanup()` function is not transferable from server to browser. (Cleanup is meant to release resources on the VM where it is running. It is not meant to be transferred to the browser.) +> - The `cleanup()` function is not transferable from server to browser. Cleanup is meant to release resources on the VM where it is running. It is not meant to be transferred to the browser. This example shows how to implement a debounce feature using the `cleanup()` function. @@ -321,7 +322,7 @@ Sometimes a task needs to run only on the browser and after rendering, in that c - runs after initial rendering. - does not block rendering. -> **Caution**: The `useVisibleTask$()` should be used as a last resort, because it eagerly executes code on the client. Qwik through [resumability]() goes out of its way to delay the execution of code on the client, and `useVisibleTask$()` is an escape hatch that should be used with caution. See [Best Practices](/docs/(qwikcity)/guides/best-practices/index.mdx#dont-register-events-eagerly-with-usevisibletask) for more details. +> **Caution**: The `useVisibleTask$()` should be used as a last resort, because it eagerly executes code on the client. Qwik, through [resumability](), goes out of its way to delay the execution of code on the client, and `useVisibleTask$()` is an escape hatch that should be used with caution. See [Best Practices](/docs/(qwikcity)/guides/best-practices/index.mdx#dont-register-events-eagerly-with-usevisibletask) for more details. > If you need to run a task on a client consider `useTask$()` with a server guard. > > @@ -358,8 +359,8 @@ Sometimes a task needs to run only on the browser and after rendering, in that c > ``` > > -> In the above example the `useTask$()` is guarded by `isServer`. The `track()` is before the guard which -> allows the server to set up the subscription but does not execute any code on the server. The client +> In the above example the `useTask$()` is guarded by `isServer`. The `track()` function is placed before the guard, which +> allows the server to set up the subscription without executing any code on the server. The client > then executes the `useTask$()` once the `text` signal changes. This example shows how to use `useVisibleTask$()` to initialize a clock on the browser only when the clock component becomes visible. @@ -401,11 +402,11 @@ const Clock = component$<{ isRunning: Signal }>(({ isRunning }) => { ``` -> Notice how the clock's `useVisibleTask$()` does not run until the `` component became visible. The default behavior of `useVisibleTask$()` is to run the task when the component becomes visible. This behavior is implemented through [intersection observers](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). +> Notice how the clock's `useVisibleTask$()` does not run until the `` component becomes visible. The default behavior of `useVisibleTask$()` is to run the task when the component becomes visible. This behavior is implemented through [intersection observers](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). ### Option `eagerness` -At times it is desirable to run `useVisibleTask$()` eagerly as soon as the application is loaded in the browser. In that case the `useVisibleTask$()` needs to run in eager mode. This is done by using the `{ strategy: 'document-ready' }`. +At times it is desirable to run `useVisibleTask$()` eagerly as soon as the application is loaded in the browser. In that case, the `useVisibleTask$()` needs to run in eager mode. This is done by using the `{ strategy: 'document-ready' }`. ```tsx @@ -451,7 +452,7 @@ const Clock = component$<{ isRunning: Signal }>(({ isRunning }) => { ### Advanced: Time of running, and managing visibility with CSS -Internally, `useVisibleTask$` is implemented by adding an attribute on the first rendered component (either the returned component or in case of a Fragment, its first child). With the standard `eagerness`, this means that if the first rendered component is hidden, the task will not run. +Internally, `useVisibleTask$` is implemented by adding an attribute to the first rendered component (either the returned component or in the case of a Fragment, its first child). With the standard `eagerness`, this means that if the first rendered component is hidden, the task will not run. This means that you can use CSS to influence when the task runs. For example, if the task should only run on a mobile device, you can return a `
` (in the case of Tailwind CSS). From 2d37f7054d62bfb3b244e57035ce26bc49b49ce8 Mon Sep 17 00:00:00 2001 From: Jay Brass <92528213+Jemsco@users.noreply.github.com> Date: Wed, 1 May 2024 17:24:40 -0400 Subject: [PATCH 2/3] docs: Update component/tasks index.mdx verbiage and rephrasing --- .../docs/src/routes/docs/(qwik)/components/tasks/index.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/docs/src/routes/docs/(qwik)/components/tasks/index.mdx b/packages/docs/src/routes/docs/(qwik)/components/tasks/index.mdx index ce87601a2ab..3cac7a3c710 100644 --- a/packages/docs/src/routes/docs/(qwik)/components/tasks/index.mdx +++ b/packages/docs/src/routes/docs/(qwik)/components/tasks/index.mdx @@ -50,8 +50,10 @@ Sometimes a task needs to run only on the browser and after rendering, in that c Sometimes a task should fetch data asynchronously and produce a signal (and not block rendering), in that case, you should use [`useResource$()`](/docs/components/state/#useresource). ## Lifecycle +Resumability is "Lazy execution", it's the ability to build the "framework state" (component boundaries, etc) on the server, and have it exist on the client without re-executing the framework again. -Thanks to [Resumability](/docs/(qwik)/concepts/resumable/index.mdx), the component's lifetime and lifecycle can extend across server and browser runtimes. This means the component might initially render on the server or directly in the browser. Regardless of where it is rendered, the lifecycle order remains the same, differing only in execution environment (server vs browser). +The application environment—whether client-side or server-side—is determined by user interactions. In server-side rendering, the application initially renders on the server. +When the user interacts with the application, it resumes on the client-side, continuing from the state left by the server. This approach ensures efficient and responsive user experiences by leveraging both environments based on interaction. > **Note**: For systems that use hydration the execution of the application happens twice. Once on a server (SSR/SSG) and once on the browser (hydration). This is why many frameworks have "effects" which only execute on the browser. That means that the code that runs on the server is different than the code that runs on the browser. Qwik execution is unified, meaning if the code has already been executed on the server it does not re-execute it on the browser. From 1447b729a1c65e2d9eb393801c9afd921d08823e Mon Sep 17 00:00:00 2001 From: Jay Brass <92528213+Jemsco@users.noreply.github.com> Date: Wed, 1 May 2024 18:03:06 -0400 Subject: [PATCH 3/3] docs: update components/tasks index.mdx rephrase on mount --- .../docs/src/routes/docs/(qwik)/components/tasks/index.mdx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/docs/src/routes/docs/(qwik)/components/tasks/index.mdx b/packages/docs/src/routes/docs/(qwik)/components/tasks/index.mdx index 3cac7a3c710..954095c727b 100644 --- a/packages/docs/src/routes/docs/(qwik)/components/tasks/index.mdx +++ b/packages/docs/src/routes/docs/(qwik)/components/tasks/index.mdx @@ -158,9 +158,10 @@ Use `useTask$()` when you need to: ### On mount -Qwik does not have a specific "on-mount" hook because useTask$() without track() effectively behaves like an "on-mount" hook. +In Qwik, there isn't a specific "mount" step like in some other frameworks. Instead, components just start up directly where they're needed, either on a web server or in your browser. +This is without the the inner track function, which is used to monitor specific pieces of data. -This is because `useTask$` runs always at least once when the component is first mounted. +`useTask$` runs always at least once when the component is first mounted. ```tsx {5-8} import { component$, useTask$ } from '@builder.io/qwik';