From a0a4b58af4f1140fa306be6c88e9a2057392d8f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20O=E2=80=99Shannessy?= Date: Thu, 23 Oct 2014 20:50:27 -0700 Subject: [PATCH] [docs] Glossary Pulled in https://gist.github.com/sebmarkbage/fcb1b6ab493b0c77d589 mostly verbatim --- _data/nav_docs.yml | 2 + docs/ref-08-reconciliation.md | 1 + docs/ref-09-glossary.md | 192 ++++++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 docs/ref-09-glossary.md diff --git a/_data/nav_docs.yml b/_data/nav_docs.yml index e7c71b68..4764540e 100644 --- a/_data/nav_docs.yml +++ b/_data/nav_docs.yml @@ -77,6 +77,8 @@ title: Special Non-DOM Attributes - id: reconciliation title: Reconciliation + - id: glossary + title: React (Virtual) DOM Terminology - title: Flux items: - id: flux-overview diff --git a/docs/ref-08-reconciliation.md b/docs/ref-08-reconciliation.md index 60f669ca..0c525eb2 100644 --- a/docs/ref-08-reconciliation.md +++ b/docs/ref-08-reconciliation.md @@ -3,6 +3,7 @@ id: reconciliation title: Reconciliation permalink: reconciliation.html prev: special-non-dom-attributes.html +next: glossary.html --- React's key design decision is to make the API seem like it re-renders the whole app on every update. This makes writing applications a lot easier but is also an incredible challenge to make it tractable. This article explains how with powerful heuristics we managed to turn a O(n3) problem into a O(n) one. diff --git a/docs/ref-09-glossary.md b/docs/ref-09-glossary.md new file mode 100644 index 00000000..3d8f200b --- /dev/null +++ b/docs/ref-09-glossary.md @@ -0,0 +1,192 @@ +--- +id: glossary +title: React (Virtual) DOM Terminology +permalink: glossary.html +prev: reconciliation.html +--- + +In React's terminology, there are five core types that are important to distinguish: + +- [ReactElement / ReactElement Factory](#react-elements) +- [ReactNode](#react-nodes) +- [ReactComponent / ReactComponent Class](#react-components) + +## React Elements + +The primary type in React is the `ReactElement`. It has four properties: `type`, `props`, `key` and `ref`. It has no methods and nothing on the prototype. + +You can create one of these object through `React.createElement`. + +```javascript +var root = React.createElement('div'); +``` + +To render a new tree into the DOM, you create `ReactElement`s and pass them to `React.render` a long with a regular DOM `Element` (`HTMLElement` or `SVGElement`). `ReactElement`s are not to be confused with DOM `Element`s. A `ReactElement` is a light, stateless, immutable, virtual representation of a DOM `Element`. It is a virtual DOM. + +```javascript +React.render(root, document.body); +``` + +To add properties to a DOM element, pass a properties object as the second argument and children to the third argument. + +```javascript +var child = React.createElement('li', null, 'Text Content'); +var root = React.createElement('ul', { className: 'my-list' }, child); +React.render(root, document.body); +``` + +If you use React JSX, then these `ReactElement`s are created for you. So this is equivalent: + +```javascript +var root = ; +React.render(root, document.body); +``` + +__Factories__ + +A `ReactElement`-factory is simply a function that generates a `ReactElement` with a particular `type` property. React has a built-in helper for you to create factories. It's effectively just: + +```javascript +function createFactory(type){ + return React.createElement.bind(null, type); +} +``` + +It allows you to create a convenient short-hand instead of typing out `React.createElement('div')` all the time. + +```javascript +var div = React.createFactory('div'); +var root = div({ className: 'my-div' }); +React.render(root, document.body); +``` + +React already have built-in factories for common HTML tags: + +```javascript +var root = React.DOM.ul({ className: 'my-list' }, + React.DOM.li(null, 'Text Content') + ); +``` + +If you are using JSX you have no need for factories. JSX already provides a convenient short-hand for creating `ReactElement`s. + + +## React Nodes + +A `ReactNode` can be either: +- `ReactElement` +- `string` (aka `ReactText`) +- `number` (aka `ReactText`) +- Array of `ReactNode`s (aka `ReactFragment`) + +These are used as properties of other `ReactElement`s to represent children. Effectively they create a tree of `ReactElement`s. + + +## React Components + +You can use React using only `ReactElement`s but to really take advantage of React, you'll want to use `ReactComponent`s to create encapsulations with embedded state. + +A `ReactComponent` Class is simply just a JavaScript class (or "constructor function"). + +```javascript +var MyComponent = React.createClass({ + render: function() { + ... + } +}); +``` + +When this constructor is invoked it is expected to return an object with at least a `render` method on it. This object is referred to as a `ReactComponent`. + +```javascript +var component = new MyComponent(props); // never do this +``` + +Other than for testing, you would normally __never__ call this constructor yourself. React calls it for you. + +Instead, you pass the `ReactComponent` Class to `createElement` you get a `ReactElement`. + +```javascript +var element = React.createElement(MyComponent); +``` + +OR using JSX: + +```javascript +var element = ; +``` + +When this is passed to `React.render`, React will call the constructor for you and create a `ReactComponent`, which returned. + +```javascript +var component = React.render(element, document.body); +``` + +If you keep calling `React.render` with the same type of `ReactElement` and the same container DOM `Element` it always returns the same instance. This instance is stateful. + +```javascript +var componentA = React.render(, document.body); +var componentB = React.render(, document.body); +componentA === componentB; // true +``` + +This is why you shouldn't construct your own instance. Instead, `ReactElement` is a virtual `ReactComponent` before it gets constructed. An old and new `ReactElement` can be compared to see if a new `ReactComponent` instance is created or if the existing one is reused. + +The `render` method of a `ReactComponent` is expected to return another `ReactElement`. This allows these components to be composed. Ultimately the render resolves into `ReactElement` with a `string` tag which instantiates a DOM `Element` instance and inserts it into the document. + + +## Formal Type Definitions + +__Entry Point__ + +``` +React.render = (ReactElement, HTMLElement | SVGElement) => ReactComponent; +``` + +__Nodes and Elements__ + +``` +type ReactNode = ReactElement | ReactFragment | ReactText; + +type ReactElement = ReactComponentElement | ReactDOMElement; + +type ReactDOMElement = { + type : string, + props : { + children : ReactNodeList, + className : string, + etc. + }, + key : string | boolean | number | null, + ref : string | null +}; + +type ReactComponentElement = { + type : ReactClass, + props : TProps, + key : string | boolean | number | null, + ref : string | null +}; + +type ReactFragment = Array; + +type ReactNodeList = ReactNode | ReactEmpty; + +type ReactText = string | number; + +type ReactEmpty = null | undefined | boolean; +``` + +__Classes and Components__ + +``` +type ReactClass = (TProps) => ReactComponent; + +type ReactComponent = { + props : TProps, + render : () => ReactElement +}; +``` +