From 91f8ffef124186db8af29641fe1d44ecca36dee1 Mon Sep 17 00:00:00 2001 From: Ben Alpert Date: Thu, 23 Oct 2014 00:45:33 -0700 Subject: [PATCH 01/15] Fix typo in 0.12 RC blog post --- _posts/2014-10-16-react-v0.12-rc1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2014-10-16-react-v0.12-rc1.md b/_posts/2014-10-16-react-v0.12-rc1.md index 95076898..56031451 100644 --- a/_posts/2014-10-16-react-v0.12-rc1.md +++ b/_posts/2014-10-16-react-v0.12-rc1.md @@ -106,7 +106,7 @@ You do NOT need to change the way to define `key` and `ref`, only if you need to ## Breaking Change: Default Props Resolution -This is a subtle difference but `defaultProps` are now resolved at `ReactElement` creation time instead of when it's mounted. This is means that we can avoid allocating an extra object for the resolve props. +This is a subtle difference but `defaultProps` are now resolved at `ReactElement` creation time instead of when it's mounted. This is means that we can avoid allocating an extra object for the resolved props. You will primarily see this breaking if you're also using `transferPropsTo`. From 5b70c84e8d0b7c4635d2de1ce595d04e223062a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20O=E2=80=99Shannessy?= Date: Wed, 22 Oct 2014 18:07:19 -0700 Subject: [PATCH 02/15] Update properties/elements --- docs/ref-04-tags-and-attributes.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/ref-04-tags-and-attributes.md b/docs/ref-04-tags-and-attributes.md index c0d01081..25173e1c 100644 --- a/docs/ref-04-tags-and-attributes.md +++ b/docs/ref-04-tags-and-attributes.md @@ -20,8 +20,8 @@ button canvas caption cite code col colgroup data datalist dd del details dfn dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 head header hr html i iframe img input ins kbd keygen label legend li link main map mark menu menuitem meta meter nav noscript object ol optgroup option -output p param pre progress q rp rt ruby s samp script section select small -source span strong style sub summary sup table tbody td textarea tfoot th +output p param picture pre progress q rp rt ruby s samp script section select +small source span strong style sub summary sup table tbody td textarea tfoot th thead time title tr track u ul var video wbr ``` @@ -52,15 +52,15 @@ For a list of events, see [Supported Events](/react/docs/events.html). These standard attributes are supported: ``` -accept accessKey action allowFullScreen allowTransparency alt async -autoComplete autoFocus autoPlay cellPadding cellSpacing charSet checked +accept acceptCharset accessKey action allowFullScreen allowTransparency alt +async autoComplete autoPlay cellPadding cellSpacing charSet checked classID className cols colSpan content contentEditable contextMenu controls coords crossOrigin data dateTime defer dir disabled download draggable encType form formNoValidate frameBorder height hidden href hrefLang htmlFor httpEquiv icon -id label lang list loop max maxLength mediaGroup method min multiple muted -name noValidate open pattern placeholder poster preload radioGroup readOnly rel -required role rows rowSpan sandbox scope scrollLeft scrolling scrollTop -seamless selected shape size span spellCheck src srcDoc srcSet start step +id label lang list loop manifest max maxLength media mediaGroup method min +multiple muted name noValidate open pattern placeholder poster preload +radioGroup readOnly rel required role rows rowSpan sandbox scope scrolling +seamless selected shape size sizes span spellCheck src srcDoc srcSet start step style tabIndex target title type useMap value width wmode ``` From 12b9311066d08f3caaad0912ee7d9f12baf8923b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20O=E2=80=99Shannessy?= Date: Wed, 22 Oct 2014 18:30:11 -0700 Subject: [PATCH 03/15] React.renderComponent -> React.render This covers most everything. The perf suite still needs work for the Element updates. And the server rendering example needs to be done wholesale. --- _js/examples/hello.js | 4 ++-- _js/examples/markdown.js | 4 ++-- _js/examples/timer.js | 4 ++-- _js/examples/todo.js | 4 ++-- _js/html-jsx.js | 2 +- _js/jsx-compiler.js | 4 ++-- _js/live_editor.js | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/_js/examples/hello.js b/_js/examples/hello.js index 3805db43..b71430a8 100644 --- a/_js/examples/hello.js +++ b/_js/examples/hello.js @@ -5,10 +5,10 @@ var HelloMessage = React.createClass({\n\ }\n\ });\n\ \n\ -React.renderComponent(, mountNode);\ +React.render(, mountNode);\ "; -React.renderComponent( +React.render( , document.getElementById('helloExample') ); diff --git a/_js/examples/markdown.js b/_js/examples/markdown.js index 6be96d5c..956d81de 100644 --- a/_js/examples/markdown.js +++ b/_js/examples/markdown.js @@ -28,10 +28,10 @@ var MarkdownEditor = React.createClass({\n\ }\n\ });\n\ \n\ -React.renderComponent(, mountNode);\ +React.render(, mountNode);\ "; -React.renderComponent( +React.render( , document.getElementById('markdownExample') ); diff --git a/_js/examples/timer.js b/_js/examples/timer.js index 2ca876a2..c54e8b4f 100644 --- a/_js/examples/timer.js +++ b/_js/examples/timer.js @@ -19,10 +19,10 @@ var Timer = React.createClass({\n\ }\n\ });\n\ \n\ -React.renderComponent(, mountNode);\ +React.render(, mountNode);\ "; -React.renderComponent( +React.render( , document.getElementById('timerExample') ); diff --git a/_js/examples/todo.js b/_js/examples/todo.js index 3db2b29a..6c628cea 100644 --- a/_js/examples/todo.js +++ b/_js/examples/todo.js @@ -33,10 +33,10 @@ var TodoApp = React.createClass({\n\ );\n\ }\n\ });\n\ -React.renderComponent(, mountNode);\ +React.render(, mountNode);\ "; -React.renderComponent( +React.render( , document.getElementById('todoExample') ); diff --git a/_js/html-jsx.js b/_js/html-jsx.js index b76d0254..d7525a83 100644 --- a/_js/html-jsx.js +++ b/_js/html-jsx.js @@ -78,5 +78,5 @@ var HELLO_COMPONENT = "\ } }); - React.renderComponent(, document.getElementById('jsxCompiler')); + React.render(, document.getElementById('jsxCompiler')); }()); diff --git a/_js/jsx-compiler.js b/_js/jsx-compiler.js index 6eb2f1e6..28364eb8 100644 --- a/_js/jsx-compiler.js +++ b/_js/jsx-compiler.js @@ -5,7 +5,7 @@ var HelloMessage = React.createClass({\n\ }\n\ });\n\ \n\ -React.renderComponent(, mountNode);\ +React.render(, mountNode);\ "; function transformer(harmony, code) { @@ -39,7 +39,7 @@ var CompilerPlayground = React.createClass({ ); }, }); -React.renderComponent( +React.render( , document.getElementById('jsxCompiler') ); diff --git a/_js/live_editor.js b/_js/live_editor.js index bfd8595d..4e453a79 100644 --- a/_js/live_editor.js +++ b/_js/live_editor.js @@ -190,7 +190,7 @@ var ReactPlayground = React.createClass({ try { var compiledCode = this.compileCode(); if (this.props.renderCode) { - React.renderComponent( + React.render( , mountNode ); @@ -199,7 +199,7 @@ var ReactPlayground = React.createClass({ } } catch (err) { this.setTimeout(function() { - React.renderComponent( + React.render(
{err.toString()}
, mountNode ); 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 04/15] [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 =
    +
  • Text Content
  • +
; +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 +}; +``` + From f9effa598f1d433aed47e5ffff32b4cdfc1c9aca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20O=E2=80=99Shannessy?= Date: Thu, 23 Oct 2014 21:13:18 -0700 Subject: [PATCH 05/15] Use --harmomy in docs examples for cleaner code --- Rakefile | 4 +-- _js/examples/hello.js | 18 +++++----- _js/examples/markdown.js | 64 +++++++++++++++++----------------- _js/examples/timer.js | 46 ++++++++++++------------ _js/examples/todo.js | 75 ++++++++++++++++++++-------------------- 5 files changed, 104 insertions(+), 103 deletions(-) diff --git a/Rakefile b/Rakefile index 44a3e114..6a7454ba 100644 --- a/Rakefile +++ b/Rakefile @@ -4,12 +4,12 @@ require('yaml') desc "generate js from jsx" task :js do - system "../bin/jsx _js js" + system "../bin/jsx --harmony _js js" end desc "watch js" task :watch do - Process.spawn "../bin/jsx --watch _js js" + Process.spawn "../bin/jsx --watch --harmony _js js" Process.waitall end diff --git a/_js/examples/hello.js b/_js/examples/hello.js index b71430a8..61a5e732 100644 --- a/_js/examples/hello.js +++ b/_js/examples/hello.js @@ -1,12 +1,12 @@ -var HELLO_COMPONENT = "\ -var HelloMessage = React.createClass({\n\ - render: function() {\n\ - return
Hello {this.props.name}
;\n\ - }\n\ -});\n\ -\n\ -React.render(, mountNode);\ -"; +var HELLO_COMPONENT = ` +var HelloMessage = React.createClass({ + render: function() { + return
Hello {this.props.name}
; + } +}); + +React.render(, mountNode); +`; React.render( , diff --git a/_js/examples/markdown.js b/_js/examples/markdown.js index 956d81de..cc43db49 100644 --- a/_js/examples/markdown.js +++ b/_js/examples/markdown.js @@ -1,35 +1,35 @@ -var MARKDOWN_COMPONENT = "\ -var converter = new Showdown.converter();\n\ -\n\ -var MarkdownEditor = React.createClass({\n\ - getInitialState: function() {\n\ - return {value: 'Type some *markdown* here!'};\n\ - },\n\ - handleChange: function() {\n\ - this.setState({value: this.refs.textarea.getDOMNode().value});\n\ - },\n\ - render: function() {\n\ - return (\n\ -
\n\ -

Input

\n\ - \n\ -

Output

\n\ - \n\ -
\n\ - );\n\ - }\n\ -});\n\ -\n\ -React.render(, mountNode);\ -"; +var MARKDOWN_COMPONENT = ` +var converter = new Showdown.converter(); + +var MarkdownEditor = React.createClass({ + getInitialState: function() { + return {value: 'Type some *markdown* here!'}; + }, + handleChange: function() { + this.setState({value: this.refs.textarea.getDOMNode().value}); + }, + render: function() { + return ( +
+

Input

+