Skip to content

Commit 7a9565d

Browse files
Brian Kimbrainkim
Brian Kim
authored andcommitted
tweak docs
1 parent 22c9462 commit 7a9565d

12 files changed

+203
-138
lines changed

website/documents/guides/01-getting-started.md

+18-12
Original file line numberDiff line numberDiff line change
@@ -257,18 +257,24 @@ renderer.render(<Timer />, document.body);
257257

258258
```jsx live
259259
import {renderer} from "@b9g/crank/dom";
260+
async function Definition({word}) {
261+
// API courtesy https://dictionaryapi.dev
262+
const res = await fetch(`https://api.dictionaryapi.dev/api/v2/entries/en/${word}`);
263+
const data = await res.json();
264+
if (!Array.isArray(data)) {
265+
return <p>No definition found for {word}</p>;
266+
}
260267

261-
async function QuoteOfTheDay() {
262-
const res = await fetch("https://favqs.com/api/qotd");
263-
const {quote} = await res.json();
264-
return (
265-
<p>
266-
“{quote.body}” – <a href={quote.url}>{quote.author}</a>
267-
</p>
268-
);
268+
const {phonetic, meanings} = data[0];
269+
const {partOfSpeech, definitions} = meanings[0];
270+
const {definition} = definitions[0];
271+
return <>
272+
<p>{word} <code>{phonetic}</code></p>
273+
<p><b>{partOfSpeech}.</b> {definition}</p>
274+
</>;
269275
}
270276

271-
renderer.render(<QuoteOfTheDay />, document.body);
277+
await renderer.render(<Definition word="framework" />, document.body);
272278
```
273279

274280
### A Loading Component
@@ -315,10 +321,10 @@ function *RandomDogApp() {
315321
for ({} of this) {
316322
yield (
317323
<Fragment>
318-
<div>
319-
<button>Show me another dog.</button>
320-
</div>
321324
<RandomDogLoader throttle={throttle} />
325+
<p>
326+
<button>Show me another dog.</button>
327+
</p>
322328
</Fragment>
323329
);
324330
}

website/documents/guides/02-elements.md

+4-6
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@ import {createElement} from "@b9g/crank";
2727
const el = createElement("div", {id: "element"}, "An element");
2828
```
2929

30-
Identifiers like `createElement`, `Fragment` must be manually imported.
31-
32-
The automatic transform turns JSX elements into function calls from an automatically imported namespace.
30+
With the classic transform, the `createElement` function must be manually imported. The automatic transform turns JSX elements into function calls from an automatically imported namespace.
3331

3432
```jsx
3533
/** @jsxImportSource @b9g/crank */
@@ -62,11 +60,11 @@ const profile = _jsxs("div", {
6260

6361
```
6462

65-
The automatic transform has the benefit of not requiring manual imports. Beyond this fact, there is no difference between the two transforms, and the `_jsx()`/`_jsxs()` functions are wrappers around `createElement()`.
63+
The automatic transform has the benefit of not requiring manual imports. Beyond this fact, there is no difference between the two transforms, and the provided `_jsx()`/`_jsxs()` functions are wrappers around `createElement()`.
6664

6765
## Renderers
6866

69-
Crank ships with two renderer subclasses for the web: one for managing DOM nodes in a front-end application, available through the module `@b9g/crank/dom`, and one for creating HTML strings, available through the module `@b9g/crank/html`. You can use these modules to render interactive user interfaces in the browser and HTML responses on the server.
67+
Crank provides two renderer subclasses for the web: one for managing DOM nodes in a front-end application, available through the module `@b9g/crank/dom`, and one for creating HTML strings, available through the module `@b9g/crank/html`. You can use these modules to render interactive user interfaces in the browser and HTML responses on the server.
7068

7169
```jsx
7270
import {renderer as DOMRenderer} from "@b9g/crank/dom";
@@ -174,7 +172,7 @@ console.log(document.body.innerHTML); // "<div>123 abc</div>"
174172
```
175173

176174
## Element Diffing
177-
Crank uses the same “virtual DOM” diffing algorithm made popular by React, where we compare elements by tag and position to reuse DOM nodes. This approach allows you to write declarative code which focuses on producing the right tree, while the framework does the dirty work of mutating the DOM efficiently.
175+
Crank uses the same “virtual DOM” diffing algorithm made popular by React, where elements are compared by tag and position to reuse DOM nodes. This approach allows you to write declarative code which focuses on producing the right tree, while the framework does the dirty work of mutating the DOM efficiently.
178176

179177
```jsx
180178
renderer.render(

website/documents/guides/03-components.md

+12-9
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ title: Components
66

77
So far, we’ve only seen and used *host elements*. By convention, all host elements use lowercase tags like `<a>` or `<div>`, and these elements are rendered as their HTML equivalents.
88

9-
However, eventually we’ll want to group these elements into reusable *components*. In Crank, components are defined with plain old JavaScript functions, including async and generator functions, which return or yield JSX elements. These functions can be referenced as element tags, and component elements are distinguished from host elements through the use of capitalized identifiers. The capitalized identifier is not just a convention but a way to tell JSX compilers to interpret the tag as an identifier rather than a literal string.
9+
However, eventually we’ll want to group these elements into reusable *components*. In Crank, all components are defined with plain old JavaScript functions which produce JSX elements. These functions can be referenced as element tags, and component elements are distinguished from host elements through the use of capitalized identifiers. The capitalized identifier is not just a convention but a way to tell JSX compilers to interpret the tag as an identifier rather than a literal string.
1010

1111
The simplest kind of component is a *function component*. When rendered, the function is invoked with the props of the element as its first argument, and the return value of the function is rendered as the element’s children.
1212

@@ -42,7 +42,7 @@ renderer.render(
4242
);
4343
```
4444

45-
The type of children is unknown, i.e. it could be an array, an element, or whatever else the caller passes in.
45+
The type of children is unknown, e.g. it could be an array, an element, or whatever else the caller passes in.
4646

4747
## Stateful Components
4848
Eventually, you’ll want to write components with local state. In Crank, we use [generator functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*) to do so. These types of components are referred to as *generator components*.
@@ -58,7 +58,7 @@ function *Counter() {
5858
count++;
5959
yield (
6060
<div>
61-
You have updated this component {count} time{count !== 1 && "s"}.
61+
This component has updated {count} time{count !== 1 && "s"}.
6262
</div>
6363
);
6464
}
@@ -72,11 +72,12 @@ renderer.render(<Counter />, document.body);
7272
By yielding elements rather than returning them, components can be made stateful using variables in the generator’s local scope. Crank uses the same diffing algorithm which reuses DOM nodes to reuse generator objects, so there will only be one execution of a generator component for a given element in the tree.
7373

7474
## The Crank Context
75-
In the preceding example, the component’s local state was updated directly when the generator was executed. This is of limited value insofar as what we usually want want is to update according to events or timers.
75+
In the preceding example, the component’s local state `count` was updated directly when the generator was re-rendered. This is of limited value insofar as what we usually want want is to update according to events or timers.
7676

7777
Crank allows components to control their own execution by passing in an object called a *context* as the `this` keyword of each component. Contexts provide several utility methods, the most important of which is the `refresh()` method, which tells Crank to update the related component instance in place.
7878

7979
```jsx live
80+
import {renderer} from "@b9g/crank/dom";
8081
function *Timer({message}) {
8182
let seconds = 0;
8283
const interval = setInterval(() => {
@@ -100,7 +101,7 @@ renderer.render(<Timer message="Seconds elapsed:" />, document.body);
100101

101102
This `<Timer>` component is similar to the `<Counter>` one, except now the state (the local variable `seconds`) is updated in a `setInterval()` callback, rather than when the component is rerendered. Additionally, the `refresh()` method is called to ensure that the generator is stepped through whenever the `setInterval()` callback fires, so that the rendered DOM actually reflects the updated `seconds` variable. Finally, the `<Timer>` component is passed a display message as a prop.
102103

103-
One important detail about the `Timer` example is that it cleans up after itself with `clearInterval()` in the `finally` block. Behind the scenes, Crank will call the `return()` method on an element’s generator object when it is unmounted.
104+
One important detail about the `Timer` example is that it cleans up after itself with `clearInterval()` in the `finally` block. Behind the scenes, Crank will call the `return()` method on the component’s generator object when it is unmounted.
104105

105106
If you hate the idea of using the `this` keyword, the context is also passed in as the second parameter of components.
106107

@@ -126,7 +127,7 @@ function *Timer({message}, ctx) {
126127

127128
## The Render Loop
128129

129-
The `<Timer>` component works, but it can be improved. Firstly, while the component is stateful, it would not update the message if it was rerendered with new props. Secondly, the `while (true)` loop can iterate infinitely if you forget to add a `yield`. To solve these issues, Crank contexts are an iterable of the latest props.
130+
The `<Timer>` component works, but it can be improved. Firstly, while the component is stateful, it would not update the message if it was rerendered with new props. Secondly, the `while (true)` loop can iterate infinitely if you forget to add a `yield`, leading to unresponsive pages. To solve both of these issues, Crank contexts are themselves an iterable of props.
130131

131132
```jsx live
132133
import {renderer} from "@b9g/crank/dom";
@@ -139,7 +140,7 @@ function *Timer({message}) {
139140

140141
for ({message} of this) {
141142
yield (
142-
<div>{message}: {seconds}</div>
143+
<div>{message} {seconds}</div>
143144
);
144145
}
145146

@@ -159,9 +160,9 @@ setTimeout(() => {
159160
}, 2500);
160161
```
161162

162-
The loop created by iterating over contexts is called the *render loop*. By replacing the `while` loop with a `for...of` loop, you can get the latest props each time the generator is resumed. It also provides benefits over `while` loops, like throwing errors if you forget to `yield`, and allowing you to write cleanup code after the loop without having to wrap the block in a `try`/`finally` block.
163+
The loop created by iterating over contexts is called the *render loop*. By replacing the `while` loop with a `for...of` loop, you can get the latest props each time the generator is resumed. It also prevents common development mistakes by throwing errors if you forget to yield, or yield multiple times in a loop. FInally, it also allows you to write cleanup code after the loop without having to wrap the entire loop in a `try`/`finally` block, as you would in a `while` loop.
163164

164-
One Crank idiom you may have noticed is that we define props in function parameters, and overwrite them using a destructuring expression in the `for...of` statement. This is an easy way to make sure those variables stay in sync with the current props of the component. For this reason, even if your component has no props, it is idiomatic to destructure props and use a `for...of` loop.
165+
One Crank idiom you may have noticed is that we define props in function parameters and overwrite them using a destructuring expression. This is an easy way to make sure those variables stay in sync with the current props of the component. For this reason, even if your component has no props, it is idiomatic to destructure props and use a `for...of` loop.
165166

166167
```jsx live
167168
import {renderer} from "@b9g/crank/dom";
@@ -172,6 +173,8 @@ function *Counter() {
172173
this.refresh();
173174
};
174175

176+
// using an empty destructuring expression means we do not need to declare
177+
// more variables when there are no props
175178
for ({} of this) {
176179
yield (
177180
<button onclick={onclick}>

website/documents/guides/04-handling-events.md

+10-14
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
title: Handling Events
33
---
44

5-
Most web applications require some measure of interactivity, where the user interface updates according to input. To facilitate this, Crank provides several ways to listen to and trigger events.
5+
Most web applications require some measure of interactivity, where the user interface updates according to interactions like clicks and form inputs. To facilitate this, Crank provides several ways to listen to and trigger events.
66

77
## DOM Event Props
8-
You can attach event callbacks to host element directly using event props. These props start with `on`, are by convention lowercase, and correspond to the event type (`onclick`, `onkeydown`). By combining event props, local variables and `this.refresh()`, you can write interactive components.
8+
You can attach event callbacks to host element directly using event props. These props start with `on`, are lowercase, and correspond to the event type (`onclick`, `onkeydown`). By combining event props, local variables and `this.refresh()`, you can write interactive components.
99

1010
```jsx live
1111
import {renderer} from "@b9g/crank/dom";
@@ -28,6 +28,8 @@ function *Counter() {
2828
renderer.render(<Counter />, document.body);
2929
```
3030

31+
Camel-cased event props are supported for compatibility reasons starting in 0.6.
32+
3133
## The EventTarget Interface
3234
As an alternative to event props, Crank contexts implement the same `EventTarget` interface used by the DOM. The `addEventListener()` method attaches a listener to a component’s root DOM node.
3335

@@ -52,11 +54,7 @@ function *Counter() {
5254
renderer.render(<Counter />, document.body);
5355
```
5456

55-
The context’s `addEventListener()` method attaches to the top-level node or nodes which each component renders, so if you want to listen to events on a nested node, you must use event delegation.
56-
57-
While the `removeEventListener()` method is implemented, you do not have to call the `removeEventListener()` method if you merely want to remove event listeners when the component is unmounted.
58-
59-
Because the event listener is attached to the outer `div`, we have to filter events by `ev.target.tagName` in the listener to make sure we’re not incrementing `count` based on clicks which don’t target the `button` element.
57+
The context’s `addEventListener()` method attaches to the top-level node or nodes which each component renders, so if you want to listen to events on a nested node, you must use event delegation. For instance, in the following example, we have to filter events by target to make sure we’re not incrementing `count` based on clicks to the outer `div`.
6058

6159
```jsx live
6260
import {renderer} from "@b9g/crank/dom";
@@ -83,6 +81,8 @@ function *Counter() {
8381
renderer.render(<Counter />, document.body);
8482
```
8583

84+
While the `removeEventListener()` method is implemented, you do not have to call the `removeEventListener()` method if you merely want to remove event listeners when the component is unmounted.
85+
8686
## Dispatching Events
8787
Crank contexts implement the full EventTarget interface, meaning you can use [the `dispatchEvent` method](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent) and [the `CustomEvent` class](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) to dispatch custom events to ancestor components:
8888

@@ -175,15 +175,11 @@ renderer.render(<CustomCounter />, document.body);
175175
Using custom events and event bubbling allows you to encapsulate state transitions within component hierarchies without the need for complex state management solutions in a way that is DOM-compatible.
176176

177177
## Event props vs EventTarget
178-
The props-based event API and the context-based EventTarget API both have their advantages. On the one hand, using event props means you can listen to exactly the element you’d like to listen to.
179-
180-
On the other hand, using the `addEventListener` method allows you to take full advantage of the EventTarget API, which includes registering passive event listeners, or listeners which are dispatched during the capture phase. Additionally, the EventTarget API can be used without referencing or accessing the child elements which a component renders, meaning you can use it to listen to elements nested in other components.
181-
182-
Crank supports both API styles for convenience and flexibility.
178+
The props-based event API and the context-based EventTarget API both have their advantages. On the one hand, using event props means you can listen to exactly the element you’d like to listen to. On the other hand, using the `addEventListener` method allows you to take full advantage of the EventTarget API, which includes registering passive event listeners, or listeners which are dispatched during the capture phase. Crank supports both API styles for convenience and flexibility.
183179

184180
## Form Elements
185181

186-
Because Crank uses explicit state updates, it doesn’t need a concept like “controlled” `value` vs “uncontrolled” `defaultValue` props in React. No update means the value is uncontrolled.
182+
Because Crank uses explicit state updates, it doesn’t require “controlled” or “uncontrolled” form props. No render means no update.
187183

188184
```jsx live
189185
import {renderer} from "@b9g/crank/dom";
@@ -213,7 +209,7 @@ function *Form() {
213209
renderer.render(<Form />, document.body);
214210
```
215211

216-
If your component is updating for other reasons, you can use the special property `copy` to prevent the input element from updating.
212+
If your component needs to update for other reasons, you can use the special `copy` prop to prevent the input element from updating. The `copy` prop is a boolean which prevents an element and children from rerendering.
217213

218214
```jsx live
219215
import {renderer} from "@b9g/crank/dom";

0 commit comments

Comments
 (0)