Reference for React Developers

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 and APIs to their equivalents in Crank.

Class-based Components

Crank uses functions exclusively for components; it does not provide a class-based component API. You can emulate most of React’s class API with the natural lifecycle of generator functions.

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 example is pseudocode which demonstrates where React’s class methods would be called relative to an async generator component. Refer to the guide on lifecycles for more information on using generator functions.

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.

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.

componentWillMount and componentDidMount

Setup code for components can be written at the top of generator components. It will not execute until the component is mounted in the tree.

shouldComponentUpdate

As an alternative to React’s shouldComponentUpdate method, you can use Copy elements to prevent the rerendering of a specific subtree. Refer to the description of Copy elements for more information.

getDerivedStateFromProps, componentWillUpdate and getSnapshotBeforeUpdate

Code which compares old and new props or state can be written directly in your components. See the section on prop updates for an example of a component which compares old and new props.

componentDidUpdate

To execute code after rendering, you can use async generator components or the schedule method. See the guide on accessing rendered values for more information.

componentWillUnmount

You can use a try/finally block to run code when a component is unmounted. You can also use the cleanup method if you’re writing extensions which don’t run in the main execution of the component.

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 guide on catching errors.

Hooks

Crank does not implement any APIs similar to React Hooks. The main appeal of hooks for library authors is that you can encapsulate entire APIs in one or two hooks. Refer to the guide on reusable logic for a description of strategies you can use to reuse logic and write library wrappers in Crank.

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.

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. Refer to the guide on accessing rendered values for more information on code which executes after rendering.

useMemo and useCallback

Because the execution of generator components is preserved, there is no need to “memoize” or “cache” callbacks or other values. You can simply assign them to a constant variable.

useImperativeHandle

Crank does not have a way to access component instances, and parent components should not access child components directly. A web component wrapper for defining custom elements with imperative APIs is planned.

Suspense and Concurrent Mode

Crank uses async functions and promises for scheduling and coordinating async processes. See the guide on 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 components by typing the props parameter of the component function. See the guide on TypeScript for detailed instructions on how to type components.

Array Children

Crank does not restrict children in JSX elements to just arrays. You can interpolate ES6 maps, sets or any other iterable into your Crank elements. Additionally, Crank does not warn you if elements in the iterable are unkeyed.

Fragments

The Fragment element works almost exactly as it does in React, except that in Crank you can also use a callback ref to access its contents.

React.cloneElement

You can clone elements using the cloneElement function.

ReactDOM.createPortal

The createPortal function is replaced by the special Portal element, whose behavior and expected props varies according to the target rendering environment. Refer to the guide on the Portal element for more information.

React.memo

See the guide on Copy tags for a demonstration of how you can use Copy elements to implement React.memo in user space.

DOM element props

The following are a list of the differences in props APIs for DOM elements.

className and htmlFor

Crank prefers attribute names rather than the JS property DOM equivalents when these names are mismatched.

<label class="my-label" for="my-id">Label</label>

In short, Crank is optimized for easy copy-pasting, which using props like className and htmlFor does not encourage. See the section on prop naming conventions for more information.

style

The style prop can be an object of CSS declarations. However, unlike React, CSS property names match the case of their CSS equivalents, and we do not add units to numbers. Additionally, Crank allows the style prop to be a CSS string as well.

  <div style="color: red"><span style={{"font-size": "16px"}}>Hello</span></div>

Refer to the guide on the style prop for more information.

Event props

Host elements can be listened to using onevent props, but the prop name will be all lowercase. Crank also provides an EventTarget API for components to add and remove event listeners from the top-level node or nodes of each component. In both cases, Crank does not use a synthetic event system or polyfill events in any way. Refer to the guide on event handling for a longer explanation of event handling in Crank.

Controlled and Uncontrolled Props

Crank does not have a concept of controlled or uncontrolled props, and does not provide defaultValue-style props for DOM elements. See the section on form elements for a detailed description of how Crank handles stateful form elements.

dangerouslySetInnerHTML

Host DOM elements accept an innerHTML prop; Crank does not provide the dangerouslySetInnerHTML={{__html}} API like React. Alternatively, you can use the special Raw tag to insert HTML strings or even DOM nodes directly into an element tree without a parent. Refer to the sections on the innerHTML prop and on the Raw tag for more information.

Keys

Crank provides keyed rendering via the special crank-key prop. The prop was renamed because “key” is a common word and because the prop is not erased from the props object passed into components.

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

Refs

Crank provides the callback-style ref API from React via the crank-ref prop. Unlike React, all elements can be read using the crank-ref prop, including Fragment elements. See the guide on the crank-ref prop.

You can also access rendered values in many other ways. Refer to this section for more information.

React Contexts

Because we refer to the this keyword of components as “the component’s context” (“controller” would have been three more characters), we refer to the equivalent concept of React’s Context API as “provisions” instead. We use the context methods provide and consume to define provisions between ancestor and descendant components. See the guide on provisions for more information.