Skip to content

Commit

Permalink
tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
brainkim committed Jul 13, 2020
1 parent 1dff8b0 commit c55e8f8
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 98 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Crank uses the same JSX syntax and diffing algorithm popularized by React, allow
### Just Functions
All components in Crank are just functions or generator functions. No classes, hooks, proxies or template languages are needed.

### Promise-fluent
### Native Promise Support
Crank provides first-class support for promises. You can use async/await directly in components, and race async components to display fallback UIs.

### Lightweight
Expand Down
10 changes: 5 additions & 5 deletions website/build.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ function Home(): Element {
</header>
<main class="features">
<div class="feature">
<h3>Declarative components</h3>
<h3>Declarative Components</h3>
<p>
Crank uses the same JSX syntax and diffing algorithm popularized
by React, allowing you to write HTML-like code directly in your
Expand All @@ -212,11 +212,11 @@ function Home(): Element {
</p>
</div>
<div class="feature">
<h3>Promises today</h3>
<h3>Native Promise Support</h3>
<p>
Crank provides first-class support for promises. You can use
async/await directly in components, and race components to display
fallback UIs.
Crank provides first-class support for promises. You can use async
functions as components, and race components to display fallback
UIs.
</p>
</div>
</main>
Expand Down
File renamed without changes.
4 changes: 0 additions & 4 deletions website/guides/06-lifecycles.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ title: Lifecycles

Crank uses generator functions rather than hooks or classes to define component lifecycles. Internally, this is achieved by calling the `next`, `return` and `throw` methods of the generator object as components are inserted, updated and removed from the element tree. As a developer, you can use the `yield`, `return`, `try`, `catch`, and `finally` keywords within your generator components to take full advantage of the generator’s natural lifecycle.

## A review of generator functions

TODO

## Returning from a generator

Usually, you’ll yield in generator components so that they can continue to respond to updates, but you may want to also `return` a final state. Unlike function components, which are called and returned once for each update, once a generator component returns, it will never update again.
Expand Down
4 changes: 2 additions & 2 deletions website/guides/07-reusable-logic.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ async function *Counter() {
- Uniform logic to dispose of resources.

**Cons:**
- Promises and async iterators can be prone to race conditions and deadlocks.
- Promises and async iterators can cause race conditions and deadlocks, without any language-level features to help you debug them.

**Use cases:**
If you use async iterators/generators already, Crank is the perfect fit for your application.
If you use async iterators/generators already, Crank is the perfect framework for your application.
1 change: 0 additions & 1 deletion website/guides/08-working-with-typescript.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,3 @@ function MyButton (props) {

## Typing provisions
By default, calls to `Context.prototype.get` and `Context.prototype.set` will be loosely typed. If you want stricter typings of these methods, you can use module augmentation to extend the `ProvisionMap` interface provided by Crank.

83 changes: 0 additions & 83 deletions website/guides/10-differences-from-react.md

This file was deleted.

157 changes: 157 additions & 0 deletions website/guides/10-mapping-react-to-crank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
---
title: Mapping React to Crank
unpublished: true
---

Though Crank is inspired by React, compatibility is a non-goal, and certain concepts may be implemented using different, non-compatible APIs. The following is a reference for React developers to help them map React concepts APIs to their equivalents in Crank.

## Class Components
Crank uses functions exclusively for components; it does not provide a class-based component API. You can emulate most of React’s Component class API with the natural lifecycle of an async generator function:

```jsx
async function *ReactComponent(props) {
let state = componentWillMount(props);
let ref = yield render(props, state);
state = componentDidMount(props, state, ref);
try {
for await (const newProps of this) {
if (shouldComponentUpdate(props, newProps, state, ref)) {
state = componentWillUpdate(props, newProps, state, ref);
ref = yield render(props, state);
state = componentDidUpdate(props, newProps, state, ref);
props = newProps;
} else {
yield <Copy />;
}
}
} catch (err) {
componentDidCatch(err);
} finally {
componentWillUnmount(ref);
}
}
```

This is pseudocode which demonstrates where the methods of React would be called relative to an async generator component. Refer to the [guide on lifecycles](./lifecycles) for more information on using generator functions.

### `setState`
Crank uses generator functions and local variables for local state. Refer to [the section on stateful components](#TTKTKTKTKTKTKTK).

### `forceUpdate`
Crank is not “reactive” in the same sense as React, in that it does not actually know when your component’s local state is updated. You can either use `Context.prototype.refresh` to manually refresh the component, much like `forceUpdate`, or you can use async generator components, which refresh automatically whenever the async generator object fulfills.

### `defaultProps`
Crank doesn’t have a `defaultProps` implementation. Instead, you can provide default values when destructuring props.

### `shouldComponentUpdate`
Components themselves do not provide a way to prevent updates to themselves. Instead, you can use `Copy` elements to prevent the rerendering of a specific subtree. [Refer to the description of `Copy` elements](#TTKTKTK) for more information.

### `componentWillMount` and `componentDidMount`
Setup code can simply be written at the top of a generator component.

### getDerivedStateFromProps`, `componentWillUpdate` and `getSnapshotBeforeUpdate`
Code which compares old and new props or state and performs side-effects can be written directly in your components. See the section on [`prop updates`](#TK) for examples of comparing old and new props. Additionally, check out the [`Context.prototoype.schedule`](#TKTKTK), which takes a callback which is called whenever the component commits.

### `componentWillUnmount`
You can use `try`/`finally` to run code when the component is unmounted. You can also use the [`Context.prototype.cleanup`] method if you’re writing extensions which don’t run in the main execution of the component.

### `componentDidUpdate`
Crank uses the special `Copy` element to prevent child updates. See the guide on the `Copy` element to see how you might reimplement `React.memo` directly in user space.

### Error Boundaries/`componentDidCatch`
To catch errors which occur in child components, you can use generator components and wrap `yield` operations in a `try`/`catch` block. Refer to [the relevant section in guides](#TK).

## Hooks
Crank does not implement any APIs similar to React Hooks. The following are alternatives to specific hooks.

### `useState` and `useReducer`
Crank uses generator functions and local variables for local state. Refer to [the section on stateful components](#TTKTKTKTKTKTKTK).

### `useEffect` and `useLayoutEffect`
Crank does not have any requirements that rendering should be “pure.” In other words, you can trigger side-effects directly while rendering because Crank does not execute components more times than you might expect.

### `useMemo`/`useCallback`
TTKTK

### `useImperativeHandle`
Crank does not yet have a way to access component instances, and parent components should not access child contexts directly. An imperative wrapper which uses web components is planned.

### Custom Hooks
The main appeal of hooks for library authors is that you can encapsulate shared logic in hooks. Refer to the [guide on reusable logic](./reusable-logic) for some patterns for reusing logic between components.

## Suspense and Concurrent Mode
Crank does not implement any sort of Suspense-like API. As an alternative, you can use async functions and async generator functions directly. See the [guide on async components](./async-components) for an introduction to async components, as well as a demonstration of how you can implement the `Suspense` component directly in user space.

## `PropTypes`
Crank is written in TypeScript, and you can add type checking to component elements by typing the props parameter of the component function.

## Fragments and array children
There’s no reason to restrict children in JSX elements to just arrays. You can interpolate ES6 Maps, Sets or any other user-defined iterable into your Crank elements, and Crank will simply render them in an implicit `Fragment`.

## `React.cloneElement`
You can clone elements using the `cloneElement` function.

## `ReactDOM.createPortal`
The `createPortal` function is replaced by a special `Portal` element, whose behavior and expected props varies according to the target rendering environment. Refer to [the guide on the `Portal` element](#KTKTKTKT) for more information.

## `React.memo`
You can use `Copy` elements to implement `React.memo` in user space:
```jsx
function equals(props, newProps) {
for (const name in {...props, ...newProps}) {
if (props[name] !== newProps[name]) {
return false;
}
}

return true;
}

function memo(Component) {
return function *Wrapped({props}) {
yield <Component {...props} />;
for (const newProps of this) {
if (equals(props, newProps)) {
yield <Copy />;
} else {
yield <Component {...newProps} />;
}

props = newProps;
}
};
}
```

See [the guide on component elements](#TKTKTKTK) for more information.

## DOM props
### `htmlFor` and `className`
Crank does not place any restrictions on the names of props. This means that you can write JSX like `<label class="my-label" for="my-id">Label</label>`.

### The `style` prop.
```jsx
<div style="color: red"><span style={{"font-size": "16px"}}>Hello</span></div>
```

The `style` prop value can be a `cssText` string, or an object, similar to React. Unlike React, the CSS property names match the case of their CSS equivalents, and we do not add units to numbers.

### `onevent` props
Crank provides `onevent` props, but they work using the DOM `onevent` props. Crank also provides an `EventTarget` API for components which adds and removes event listeners from the top-level nodes of each component. In both cases, Crank does not use a synthetic event API or shim events. See [the guide on events for more information](#TKTKTKTKTK).

### Controlled and Uncontrolled Props
Crank does not have a concept of controlled or uncontrolled props, and does not have `defaultValue` props.

### `dangerouslySetInnerHTML`
Crank elements accept an `innerHTML` prop. Alternatively, you can use the special `Raw` tag to insert arbitrary HTML strings or even nodes in the tree. [See the guide on the `Raw` element](#TKTK) for more information.

## Keys
Crank provides keyed rendering via the `crank-key` prop. The prop was renamed because “key” is a common word and because the prop is not passed directly into child objects.

Keys work similarly to the way they do in React. The main difference is that Crank does not require elements which appear in arrays or iterables to be keyed.

## Refs
Crank provides the callback ref API from React via the `crank-ref` prop. Crank does not TKTKTKT

## React Contexts
TKTKTKTKT

0 comments on commit c55e8f8

Please sign in to comment.