From 25468d2b7daaa16f796e2b90ed8d83b780f305b9 Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Tue, 21 Jul 2020 01:22:56 -0400 Subject: [PATCH] update custom renderer docs --- website/guides/06-special-props-and-tags.md | 8 +++--- website/guides/10-custom-renderers.md | 28 +++++++++---------- .../11-reference-for-react-developers.md | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/website/guides/06-special-props-and-tags.md b/website/guides/06-special-props-and-tags.md index f7596b06f..c6dca80be 100644 --- a/website/guides/06-special-props-and-tags.md +++ b/website/guides/06-special-props-and-tags.md @@ -138,7 +138,7 @@ You can still use the `className` and `htmlFor` props as well, but using the for Crank provides four element tags which have special meaning to the renderer, and affect element diffing and rendering output in various ways. -### Fragment +### `Fragment` Crank provides a `Fragment` tag, which allows you to render multiple children into a parent without wrapping them in another DOM node. Under the hood, iterables which appear in the element tree are also implicitly wrapped in a `Fragment` element by the renderer. ```jsx @@ -158,7 +158,7 @@ console.log(document.body.innerHTML); // "
Sibling 1
Sibling 2
" ``` -### Copy +### `Copy` It‘s often fine to rerender Crank components, because elements are diffed, persistent between renders, and unnecessary mutations usually avoided. However, you might want to prevent a child from updating when the parent rerenders, perhaps because a certain prop hasn’t changed, because you want to batch updates from the parent, or as a performance optimization. To do this, you can use the `Copy` tag to indicate to Crank that you don’t want to update a previously rendered element in that same position. ```jsx @@ -190,7 +190,7 @@ function memo(Component) { In this example, `memo` is a higher-order component, a function which takes a component and returns a component. This wrapper component compares old and new props and yields a `Copy` element if every prop is shallowly equal. A `Copy` element can appear anywhere in an element tree to prevent rerenderings, and the only props `Copy` elements take are the `crank-key` and `crank-ref` props, which work as expected. -### Portal +### `Portal` Sometimes you may want to render into a DOM node which isn’t the current parent element, or even a part of the currently rendered DOM tree. You can do this with the `Portal` tag, passing in a DOM node as its `root` prop. The Portal’s children will be rendered into the specified root element, just as if Renderer.render was called with the root value as its second argument. ```jsx @@ -219,7 +219,7 @@ console.log(root2.innerHTML); This tag is useful for creating modals or tooltips, which usually need to be rendered into separate DOM elements at the bottom of the page for visibility reasons. Events dispatched from a `Portal` element‘s child components via the `dispatchEvent` method will still bubble into parent components. -### Raw +### `Raw` Sometimes, you may want to insert raw HTML or actual DOM nodes directly into the element tree. Crank allows you to do this with the `Raw` element. The `Raw` element takes a `value` prop which is interpreted by the renderer. For the DOM renderer, if `value` is an HTML string, the renderer will parse and insert the resulting DOM nodes. If the value is already a DOM node, Crank will insert them in place. ```jsx diff --git a/website/guides/10-custom-renderers.md b/website/guides/10-custom-renderers.md index a31878dd4..4db31ec03 100644 --- a/website/guides/10-custom-renderers.md +++ b/website/guides/10-custom-renderers.md @@ -33,7 +33,7 @@ class Renderer< - `TScope` is the type of the *scope*, a renderer-specific concept for arbitrary data which can passed down the tree between host elements. Scopes are useful for passing contextual information down the tree to be used when nodes are created; for instance, the DOM renderer uses the scope to pass down information about whether we’re currently rendering in an SVG element. - `TRoot` is the type of the root node. This is the type of the second parameter passed to the `Renderer.render` method, and the `root` prop passed to `Portal` elements. It is usually the same type as `TNode` but can vary according to renderer requirements. - `TResult` describes the type of values made visible to renderer consumers. Any time Crank exposes an internal node, for instance, via the `crank-ref` callback, or as the result of yield expressions in generator components, the renderer can intercept this access and provide something other than the internal nodes, allowing renderers to hide implementation details and provide results which make more sense for a specific environment. - For example, the HTML string renderer has an internal node representation, but converts these nodes to strings before they’re exposed to consumers. This is done because the internal nodes must be referentially unique and mutated during rendering, while JavaScript strings are referentially transparent and immutable. Therefore, the `TResult` of the `HTMLRenderer` subclass is `string`. + For example, the HTML string renderer has an internal node representation, but converts these nodes to strings before they’re exposed to consumers. This is because the internal nodes must be a referentially unique object which is mutated during rendering, while JavaScript strings are referentially transparent and immutable. Therefore, the `TResult` type of the HTML renderer is `string`. ## Methods The following is a description of the signatures of internal renderer methods and when they’re executed. @@ -42,44 +42,46 @@ The following is a description of the signatures of internal renderer methods an ```ts create( - tag: string | symbol, props: Record, scope: TScope + el: Element, scope: TScope ): TNode; ``` -The `create` method is called for each host element the first time the element is committed. The tag and props parameters are the tag and props of the host element which initiated this call, and the scope is the current scope of the element. The return value is the node which will be associated with the host element. +The `create` method is called for each host element the first time the element is committed. This method is passed the current host element and scope, and should return the node which will be associated with the host element. This node will remain constant for the duration that the element is mounted in the tree. By default, this method will throw a `Not Implemented` error, so custom renderers should always implement this method. ### Renderer.prototype.patch ```ts patch( - tag: string | symbol, props: Record, node: TNode, scope: TScope, + el: Element, node: TNode, ): unknown; ``` -The `patch` method is called for each host element whenever it is committed. The tag and props are the tag and props of the associated host element, the node is the value produced by the `create` method when the value was mounted, and the scope is the current scope of the element. +The `patch` method is called for each host element whenever it is committed. This method is passed the current host element and its related node, and its return value is ignored. This method is useful for mutating nodes whenever the host element is committed. -This method is useful for mutating nodes whenever the host element is committed. Implementation is optional and its return value is ignored. +Implementation of this method is optional for renderers. ### Renderer.prototype.arrange ```ts arrange( - tag: string | symbol, props: Record, parent: TNode | TRoot, children: Array + el: Element, + parent: TNode | TRoot, + children: Array, ): unknown; ``` -The `arrange` method is called whenever an element’s children have changed. The tag and props are the tag and props of the associated host element, the parent is the value created by the create method for a host node and the `children` are the child values of all the element’s direct children. The `arrange` is also called for every root/portal element, so the parent can be of type `TRoot` as well as `TNode`. +The `arrange` method is called whenever an element’s children have changed. It is called with the current host element, the host element’s related node, and the rendered values of all the element’s descendants as an array. In addition to when a host element commits, the `arrange` method may also be called when a child refreshes or otherwise causes the host element’s rendered children to change. Because the `arrange` method is called for every root/portal element, the parent can be of type `TRoot` as well as `TNode`. This method is where the magic happens, and is useful for connecting the nodes of your target environment as an internal tree. ### Renderer.prototype.scope ```ts scope( - tag: string | symbol, props: Record, scope: TScope | undefined + el: Element, scope: TScope | undefined ): TScope; ``` -The `scope` method is called for each host or portal element as elements are mounted or updated. Unlike the other custom renderer methods, the `scope` method is called during the pre-order traversal of the tree, much as components are. The `scope` method is passed the tag and props of the relevant host element, as well as the current scope, and the return value becomes the scope argument passed to the `create` and `scope` method calls for child host elements. +The `scope` method is called for each host or portal element as elements are mounted or updated. Unlike the other custom renderer methods, the `scope` method is called during the pre-order traversal of the tree, much as components are. The `scope` method is passed the current host element and scope, and the return value becomes the scope argument passed to the `create` and `scope` method calls for child host elements. ### Renderer.prototype.escape ```ts @@ -101,12 +103,10 @@ By default, the `parse` method returns the string which was passed in. ### Renderer.prototype.dispose ```ts -dispose( - tag: string | symbol, props: Record, node: TNode -): unknown +dispose(el: Element, node: TNode): unknown ``` -When a host element is unmounted, we call the `dispose` method with the related host element’s tag, props and node. This method is useful if you need to manually release a node or clean up event listeners for garbage collection purposes. +When a host element is unmounted, we call the `dispose` method with the host element and its related node. This method is useful if you need to manually release a node or clean up event listeners for garbage collection purposes. This method is optional and its return value is ignored. diff --git a/website/guides/11-reference-for-react-developers.md b/website/guides/11-reference-for-react-developers.md index 4414d8c06..9f2e3634c 100644 --- a/website/guides/11-reference-for-react-developers.md +++ b/website/guides/11-reference-for-react-developers.md @@ -38,7 +38,7 @@ The following are specific equivalents for React methods. ### `setState` and `forceUpdate` Crank uses generator functions and local variables for local state. Refer to [the section on stateful components](./guides/components#stateful-components). -Crank is not “reactive” in the same sense as React, in that it does not actually track your component’s local state. You can either use `Context.prototype.refresh` to manually refresh the component, much like React’s `forceUpdate` method, or you can use async generator components, which refresh automatically whenever the returned async generator yields. +Crank is not “reactive” in the same sense as React, in that it does not track your component’s local state and rerender when it detects a change. You can either use the context’s `refresh` to manually refresh the component, similar to React’s `forceUpdate` method, or you can use async generator components, which refresh automatically whenever the returned async generator yields. ### `defaultProps` Crank doesn’t have a `defaultProps` implementation. Instead, you can provide default values when destructuring props. [See the guide on default props](./components#default-props).