Skip to content

Commit

Permalink
refactor: drop mutable() (QwikDev#1323)
Browse files Browse the repository at this point in the history
  • Loading branch information
manucorporat authored Sep 21, 2022
1 parent 3e9ef58 commit 632e592
Show file tree
Hide file tree
Showing 32 changed files with 579 additions and 403 deletions.
1 change: 1 addition & 0 deletions packages/docs/src/components/content-nav/content-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const ContentNav = component$(() => {
</a>
) : null}
</div>

<div class="flex-1 text-right">
{next ? (
<a class="px-3 py-1 next" href={next.href}>
Expand Down
29 changes: 0 additions & 29 deletions packages/docs/src/routes/tutorial/props/mutable/index.mdx

This file was deleted.

22 changes: 0 additions & 22 deletions packages/docs/src/routes/tutorial/props/mutable/problem/app.tsx

This file was deleted.

22 changes: 0 additions & 22 deletions packages/docs/src/routes/tutorial/props/mutable/solution/app.tsx

This file was deleted.

7 changes: 2 additions & 5 deletions packages/docs/src/routes/tutorial/props/store/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
title: Passing Stores
---

The previous tutorial introduced you `mutable()` to demonstrate that Qwik assumes all props are static to remain efficient.

Beyond the fact that typing `mutable()` is extra work, the previous example is also inefficient in its own way.
The previous tutorial introduced you how you could pass primitives and objects to components. In this tutorial, we will learn how to pass stores to components, which is way more efficient in terms of rerendering.

When you click on the `+1` button, the `<App>` is re-rendered to update the `<Display>` bindings. The re-rendering of `<App>` is needed to update the props of `<Display>`, but this process doesn't update to what the user sees, so it is a waste of resources.

Expand All @@ -14,9 +12,8 @@ A better approach is to only re-render `<Display>` component by passing in the `
Two benefits emerge by making the above change:

- The `mutable()` binding function is removed from the component.
- The `<App>` component doesn't need to be downloaded or re-rendered.

## Best Practice

A best practice to follow in Qwik features passing a store to child components rather than individual primitives. When you use primitives, you are forced to wrap them with `mutable()` to make the application work.
A best practice to follow in Qwik features passing a store to child components rather than individual primitives. When you use primitives, the parent component needs to rerender just to pass in the new value. When you pass in a store, the parent component doesn't need to rerender.
7 changes: 0 additions & 7 deletions packages/docs/src/routes/tutorial/tutorial-menu.json
Original file line number Diff line number Diff line change
Expand Up @@ -166,13 +166,6 @@
"enableClientOutput": false,
"enableSsrOutput": false
},
{
"id": "mutable",
"title": "Mutable Props",
"enableHtmlOutput": false,
"enableClientOutput": false,
"enableSsrOutput": false
},
{
"id": "store",
"title": "Passing Stores",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { component$, mutable, useStyles$ } from '@builder.io/qwik';
import { component$, useStyles$ } from '@builder.io/qwik';
import { Link, useContent, useLocation, ContentMenu } from '~qwik-city-runtime';
import styles from './breadcrumbs.css?inline';

Expand All @@ -17,7 +17,7 @@ export const Breadcrumbs = component$(() => {
<nav class="breadcrumbs">
{breadcrumbs.map((b, i) => (
<span data-test-breadcrumb={i}>
{b.href ? <Link href={mutable(b.href)}>{b.text}</Link> : b.text}
{b.href ? <Link href={b.href}>{b.text}</Link> : b.text}
</span>
))}
</nav>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ContentMenu, Link, useContent, useLocation } from '@builder.io/qwik-city';
import { component$, mutable, useStyles$ } from '@builder.io/qwik';
import { component$, useStyles$ } from '@builder.io/qwik';
import styles from './content-nav.css?inline';

export const ContentNav = component$(() => {
Expand All @@ -17,14 +17,14 @@ export const ContentNav = component$(() => {
<nav class="content-nav">
<div class="prev">
{prev ? (
<Link href={mutable(prev.href)} prefetch={true}>
<Link href={prev.href} prefetch={true}>
{prev.text}
</Link>
) : null}
</div>
<div class="next">
{next ? (
<Link href={mutable(next.href)} prefetch={true}>
<Link href={next.href} prefetch={true}>
{next.text}
</Link>
) : null}
Expand Down
14 changes: 7 additions & 7 deletions packages/qwik-city/runtime/src/app/components/header/header.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { component$, mutable, useStyles$ } from '@builder.io/qwik';
import { component$, useStyles$ } from '@builder.io/qwik';
import { Link, useLocation } from '~qwik-city-runtime';
import styles from './header.css?inline';

Expand All @@ -19,47 +19,47 @@ export default component$(() => {
<Link
href="/blog"
prefetch={true}
class={mutable({ active: pathname.startsWith('/blog') })}
class={{ active: pathname.startsWith('/blog') }}
data-test-link="blog-home"
>
Blog
</Link>
<Link
href="/docs"
prefetch={true}
class={mutable({ active: pathname.startsWith('/docs') })}
class={{ active: pathname.startsWith('/docs') }}
data-test-link="docs-home"
>
Docs
</Link>
<Link
href="/api"
prefetch={true}
class={mutable({ active: pathname.startsWith('/api') })}
class={{ active: pathname.startsWith('/api') }}
data-test-link="api-home"
>
API
</Link>
<Link
href="/products/hat"
prefetch={true}
class={mutable({ active: pathname.startsWith('/products') })}
class={{ active: pathname.startsWith('/products') }}
data-test-link="products-hat"
>
Products
</Link>
<Link
href="/about-us"
prefetch={true}
class={mutable({ active: pathname.startsWith('/about-us') })}
class={{ active: pathname.startsWith('/about-us') }}
data-test-link="about-us"
>
About Us
</Link>
<Link
href="/sign-in"
prefetch={true}
class={mutable({ active: pathname.startsWith('/sign-in') })}
class={{ active: pathname.startsWith('/sign-in') }}
data-test-link="sign-in"
>
Sign In
Expand Down
8 changes: 4 additions & 4 deletions packages/qwik-city/runtime/src/app/components/menu/menu.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { component$, mutable, useStyles$ } from '@builder.io/qwik';
import { component$, useStyles$ } from '@builder.io/qwik';
import { useContent, Link, useLocation } from '~qwik-city-runtime';
import styles from './menu.css?inline';

Expand All @@ -19,11 +19,11 @@ export const Menu = component$(() => {
<li>
<Link
data-test-menu-link={item.href}
href={mutable(item.href)}
href={item.href}
prefetch={true}
class={mutable({
class={{
'is-active': pathname === item.href,
})}
}}
>
{item.text}
</Link>
Expand Down
15 changes: 5 additions & 10 deletions packages/qwik/src/core/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,9 @@ export interface HTMLAttributes<T> extends AriaAttributes, DOMAttributes<T> {
// @internal
export const _hW: () => void;

// @internal (undocumented)
export const _IMMUTABLE: unique symbol;

// @alpha
export const implicit$FirstArg: <FIRST, REST extends any[], RET>(fn: (first: QRL<FIRST>, ...rest: REST) => RET) => (first: FIRST, ...rest: REST) => RET;

Expand Down Expand Up @@ -283,13 +286,8 @@ export type JSXTagName = keyof HTMLElementTagNameMap | Omit<string, keyof HTMLEl
// @public (undocumented)
export type MountFn<T> = () => ValueOrPromise<T>;

// @alpha
export const mutable: <T>(v: T) => MutableWrapper<T>;

// @alpha
export interface MutableWrapper<T> {
mut: T;
}
// @alpha @deprecated (undocumented)
export const mutable: <T>(v: T) => T;

// @public
export type NoSerialize<T> = (T & {
Expand Down Expand Up @@ -643,9 +641,6 @@ export const useMount$: <T>(first: MountFn<T>) => void;
// @public
export const useMountQrl: <T>(mountQrl: QRL<MountFn<T>>) => void;

// @internal (undocumented)
export const _useMutableProps: (element: Element, mutable: boolean) => void;

// @alpha
export const useOn: (event: string, eventQrl: QRL<(ev: Event) => void>) => void;

Expand Down
7 changes: 3 additions & 4 deletions packages/qwik/src/core/component/component.public.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { OnRenderProp } from '../util/markers';
import type { ComponentBaseProps, JSXChildren } from '../render/jsx/types/jsx-qwik-attributes';
import type { FunctionComponent } from '../render/jsx/types/jsx-node';
import { jsx } from '../render/jsx/jsx-runtime';
import type { MutableWrapper } from '../object/q-object';
import { SERIALIZABLE_STATE } from '../object/serializers';
import { qTest } from '../util/qdev';
import { Virtual } from '../render/jsx/utils.public';
Expand Down Expand Up @@ -49,15 +48,15 @@ export type ComponentChildren<PROPS extends {}> = PROPS extends { children: any
? never
: { children?: JSXChildren };
/**
* Extends the defined component PROPS, adding the default ones (children and q:slot) as well as the mutable variations.
* Extends the defined component PROPS, adding the default ones (children and q:slot)..
* @public
*/
export type PublicProps<PROPS extends {}> = TransformProps<PROPS> &
ComponentBaseProps &
ComponentChildren<PROPS>;

/**
* Transform the component PROPS adding the mutable equivalents, so `mutable()` can be used natively.
* Transform the component PROPS.
* @public
*/
export type TransformProps<PROPS extends {}> = {
Expand All @@ -69,7 +68,7 @@ export type TransformProps<PROPS extends {}> = {
*/
export type TransformProp<T> = T extends PropFnInterface<infer ARGS, infer RET>
? (...args: ARGS) => ValueOrPromise<RET>
: T | MutableWrapper<T>;
: T;

/**
* @alpha
Expand Down
5 changes: 1 addition & 4 deletions packages/qwik/src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,11 @@ export { useServerMount$, useServerMountQrl } from './use/use-watch';
export { useMount$, useMountQrl } from './use/use-watch';
export { useErrorBoundary } from './use/use-error-boundary';

export { _useMutableProps } from './props/props';

//////////////////////////////////////////////////////////////////////////////////////////
// Developer Low-Level API
//////////////////////////////////////////////////////////////////////////////////////////
export type { ValueOrPromise } from './util/types';
export type { NoSerialize } from './object/q-object';
export { noSerialize, mutable } from './object/q-object';
export type { MutableWrapper } from './object/q-object';
export { noSerialize, mutable, _IMMUTABLE } from './object/q-object';

export { version } from './version';
Loading

0 comments on commit 632e592

Please sign in to comment.