diff --git a/acknowledgements.html b/acknowledgements.html index 80ce1bfc7f..407621f718 100644 --- a/acknowledgements.html +++ b/acknowledgements.html @@ -435,7 +435,7 @@ -

In addition, we're grateful to Jeff Barczewski for allowing us to use the react package name on npm and to Christopher Aue for letting us use the reactjs.com domain name and the @reactjs username on Twitter.

+

In addition, we're grateful to Jeff Barczewski for allowing us to use the react package name on npm and to Christopher Aue for letting us use the reactjs.com domain name and the @reactjs username on Twitter. We'd also like to thank ProjectMoon for letting us use the flux package name on npm.

diff --git a/docs/addons.html b/docs/addons.html index 7f4e059406..bc0ba702da 100644 --- a/docs/addons.html +++ b/docs/addons.html @@ -457,6 +457,8 @@

To get the add-ons, use react-with-addons.js (and its minified counterpart) rather than the common react.js.

+

When using the react package from npm, just simply require('react/addons') instead of require('react') to get React with all of the addons.

+
diff --git a/docs/clone-with-props.html b/docs/clone-with-props.html index 34a757d870..f5606b05ab 100644 --- a/docs/clone-with-props.html +++ b/docs/clone-with-props.html @@ -447,7 +447,8 @@

cloneWithProps does not transfer the key prop to the cloned component. If you wish to preserve the key, add it to the extraProps object: js var clonedComponent = cloneWithProps(originalComponent, { key : originalComponent.props.key }); -

+ +ref is another prop that is not preserved either.

diff --git a/docs/component-api.html b/docs/component-api.html index 51839ccda9..984910f343 100644 --- a/docs/component-api.html +++ b/docs/component-api.html @@ -438,7 +438,7 @@

ReactComponent #

-

Component classes created by React.createClass() return instances of ReactComponent when called. Most of the time when you're using React you're either creating or consuming these component objects.

+

Instances of a React Component are created internally in React when rendering. These instances are reused in subsequent renders, and can be accessed in your component methods as this. The only way to get a handle to a React Component instance outside of React is by storing the return value of React.renderComponent. Inside other Components, you may use refs to achieve the same result.

setState #

setState(object nextState[, function callback])
 

Merges nextState with the current state. This is the primary method you use to trigger UI updates from event handlers and server request callbacks. In addition, you can supply an optional callback function that is executed once setState is completed and the component is re-rendered.

diff --git a/docs/component-specs.html b/docs/component-specs.html index ed8dbd0cbe..8649f5852c 100644 --- a/docs/component-specs.html +++ b/docs/component-specs.html @@ -488,7 +488,7 @@

Invoked once, both on the client and server, immediately before the initial rendering occurs. If you call setState within this method, render() will see the updated state and will be executed only once despite the state change.

Mounting: componentDidMount #

componentDidMount()
 
-

Invoked immediately after rendering occurs, only on the client (not on the server). At this point in the lifecycle, the component has a DOM representation which you can access via this.getDOMNode().

+

Invoked once, only on the client (not on the server), immediately after the initial rendering occurs. At this point in the lifecycle, the component has a DOM representation which you can access via this.getDOMNode().

If you want to integrate with other JavaScript frameworks, set timers using setTimeout or setInterval, or send AJAX requests, perform those operations in this method.

diff --git a/docs/examples.html b/docs/examples.html index 1e21dab1f0..67183e8849 100644 --- a/docs/examples.html +++ b/docs/examples.html @@ -437,29 +437,7 @@
-

Production Apps #

- -

Sample Code #

- -

Open-Source Demos #

- +

This page has moved to the GitHub wiki.

diff --git a/docs/getting-started.html b/docs/getting-started.html index 0585e8bbe5..d08635753b 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -481,6 +481,12 @@ document.getElementById('example') );
+
+

Note:

+ +

/** @jsx React.DOM */ is required. The comment parser is very strict right now; in order for it to pick up the @jsx modifier, two conditions are required. The @jsx comment block must be the first comment on the file. The comment must start with /** (/* and // will not work). If the parser can't find the @jsx comment, it will output the file without transforming it.

+
+

Then reference it from helloworld.html:

<script type="text/jsx" src="src/helloworld.js"></script>
 

Offline Transform #

@@ -497,12 +503,6 @@ document.getElementById('example') );
-
-

Note:

- -

The comment parser is very strict right now; in order for it to pick up the @jsx modifier, two conditions are required. The @jsx comment block must be the first comment on the file. The comment must start with /** (/* and // will not work). If the parser can't find the @jsx comment, it will output the file without transforming it.

-
-

Update your HTML file as below:

<!DOCTYPE html>
 <html>
diff --git a/docs/multiple-components.html b/docs/multiple-components.html
index 46fd101311..a83926f9bd 100644
--- a/docs/multiple-components.html
+++ b/docs/multiple-components.html
@@ -528,6 +528,43 @@
 

When React reconciles the keyed children, it will ensure that any child with key will be reordered (instead of clobbered) or destroyed (instead of reused).

+

The key should always be supplied directly to the components in the array, not to the container HTML child of each component in the array:

+
// WRONG!
+var ListItemWrapper = React.createClass({
+  render: function() {
+    return <li key={this.props.data.id}>{this.props.data.text}</li>;
+  }
+});
+var MyComponent = React.createClass({
+  render: function() {
+    return (
+      <ul>
+        {this.props.results.map(function(result) {
+          return <ListItemWrapper data={result}/>;
+        })}
+      </ul>
+    );
+  }
+});
+
+// Correct :)
+var ListItemWrapper = React.createClass({
+  render: function() {
+    return <li>{this.props.data.text}</li>;
+  }
+});
+var MyComponent = React.createClass({
+  render: function() {
+    return (
+      <ul>
+        {this.props.results.map(function(result) {
+           return <ListItemWrapper key={result.id} data={result}/>;
+        })}
+      </ul>
+    );
+  }
+});
+

You can also key children by passing an object. The object keys will be used as key for each value. However it is important to remember that JavaScript does not guarantee the ordering of properties will be preserved. In practice browsers will preserve property order except for properties that can be parsed as a 32-bit unsigned integers. Numeric properties will be ordered sequentially and before other properties. If this happens React will render components out of order. This can be avoided by adding a string prefix to the key:

  render: function() {
     var items = {};
diff --git a/docs/reconciliation.html b/docs/reconciliation.html
index 7faac624c8..e6331769a0 100644
--- a/docs/reconciliation.html
+++ b/docs/reconciliation.html
@@ -509,7 +509,7 @@ renderB: <div><span key=Trade-offs #
 

It is important to remember that the reconciliation algorithm is an implementation detail. React could re-render the whole app on every action, the end-result would be the same. We are regularly refining the heuristics in order to make common use cases faster.

-

In the current implementation, you can express the fact that a sub-tree has been moved between siblings, but you cannot tell that it has moved somewhere else. The algorithm will re-render that full sub-tree.

+

In the current implementation, you can express the fact that a sub-tree has been moved amongst its siblings, but you cannot tell that it has moved somewhere else. The algorithm will re-render that full sub-tree.

Because we rely on two heuristics, if the assumptions behind them are not met, performance will suffer.

diff --git a/docs/reusable-components.html b/docs/reusable-components.html index 64773ce408..8471fa8a3d 100644 --- a/docs/reusable-components.html +++ b/docs/reusable-components.html @@ -437,7 +437,7 @@
-

When designing interfaces, break down the common design elements (buttons, form fields, layout components, etc) into reusable components with well-defined interfaces. That way, the next time you need to build some UI you can write much less code, which means faster development time, less bugs, and less bytes down the wire.

+

When designing interfaces, break down the common design elements (buttons, form fields, layout components, etc) into reusable components with well-defined interfaces. That way, the next time you need to build some UI you can write much less code, which means faster development time, fewer bugs, and fewer bytes down the wire.

Prop Validation #

As your app grows it's helpful to ensure that your components are used correctly. We do this by allowing you to specify propTypes. React.PropTypes exports a range of validators that can be used to make sure the data you receive is valid. When an invalid value is provided for a prop, a warning will be shown in the JavaScript console. Note that for performance reasons propTypes is only checked in development mode. Here is an example documenting the different validators provided:

React.createClass({
diff --git a/docs/test-utils.html b/docs/test-utils.html
index 37186d0942..96a3a71b74 100644
--- a/docs/test-utils.html
+++ b/docs/test-utils.html
@@ -452,7 +452,7 @@
 

renderIntoDocument #

ReactComponent renderIntoDocument(ReactComponent instance)
 

Render a component into a detached DOM node in the document. This function requires a DOM.

-

mockComponent #

object mockComponent(function componentClass, string? tagName)
+

mockComponent #

object mockComponent(function componentClass, string? mockTagName)
 

Pass a mocked component module to this method to augment it with useful methods that allow it to be used as a dummy React component. Instead of rendering as usual, the component will become a simple <div> (or other tag if mockTagName is provided) containing any provided children.

isDescriptorOfType #

boolean isDescriptorOfType(ReactDescriptor descriptor, function componentClass)
diff --git a/docs/tutorial.html b/docs/tutorial.html
index d12bbf3ab9..f23b451dde 100644
--- a/docs/tutorial.html
+++ b/docs/tutorial.html
@@ -902,12 +902,12 @@
   handleSubmit: function(e) {
     e.preventDefault();
     var author = this.refs.author.getDOMNode().value.trim();
-    var text = this.refs.text.getDOMNode().value.trim();
-    if (!text || !author) {
+    var text = this.refs.text.getDOMNode().value.trim();
+    if (!text || !author) {
       return;
     }
-    this.props.onCommentSubmit({author: author, text: text});
-    this.refs.author.getDOMNode().value = '';
+    this.props.onCommentSubmit({author: author, text: text});
+    this.refs.author.getDOMNode().value = '';
     this.refs.text.getDOMNode().value = '';
     return;
   },
diff --git a/docs/videos.html b/docs/videos.html
index 0dfdbd6651..550d9bdb0c 100644
--- a/docs/videos.html
+++ b/docs/videos.html
@@ -524,6 +524,10 @@
 
 

"Rethinking Web App Development at Facebook" - Facebook F8 Conference 2014 #

+

React and Flux: Building Applications with a Unidirectional Data Flow - Forward JS 2014 #

+ + +

Facebook engineers Bill Fisher and Jing Chen talk about Flux and React, and how using an application architecture with a unidirectional data flow cleans up a lot of their code.

diff --git a/html-jsx.html b/html-jsx.html index 0910069bc6..dc84d55dbb 100644 --- a/html-jsx.html +++ b/html-jsx.html @@ -60,7 +60,7 @@

HTML to JSX Compiler

- +
diff --git a/js/html-jsx-lib.js b/js/html-jsx-lib.js index 02b36bcf1f..2e94a4db4f 100644 --- a/js/html-jsx-lib.js +++ b/js/html-jsx-lib.js @@ -1,482 +1,7 @@ -/** - * Copyright 2013-2014 Facebook, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * This is a very simple HTML to JSX converter. It turns out that browsers - * have good HTML parsers (who would have thought?) so we utilise this by - * inserting the HTML into a temporary DOM node, and then do a breadth-first - * traversal of the resulting DOM tree. - */ -;(function(global) { - 'use strict'; - - // https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeType - var NODE_TYPE = { - ELEMENT: 1, - TEXT: 3, - COMMENT: 8 - }; - var ATTRIBUTE_MAPPING = { - 'for': 'htmlFor', - 'class': 'className' - }; - - /** - * Repeats a string a certain number of times. - * Also: the future is bright and consists of native string repetition: - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat - * - * @param {string} string String to repeat - * @param {number} times Number of times to repeat string. Integer. - * @see http://jsperf.com/string-repeater/2 - */ - function repeatString(string, times) { - if (times === 1) { - return string; - } - if (times < 0) { throw new Error(); } - var repeated = ''; - while (times) { - if (times & 1) { - repeated += string; - } - if (times >>= 1) { - string += string; - } - } - return repeated; - } - - /** - * Determine if the string ends with the specified substring. - * - * @param {string} haystack String to search in - * @param {string} needle String to search for - * @return {boolean} - */ - function endsWith(haystack, needle) { - return haystack.slice(-needle.length) === needle; - } - - /** - * Trim the specified substring off the string. If the string does not end - * with the specified substring, this is a no-op. - * - * @param {string} haystack String to search in - * @param {string} needle String to search for - * @return {string} - */ - function trimEnd(haystack, needle) { - return endsWith(haystack, needle) - ? haystack.slice(0, -needle.length) - : haystack; - } - - /** - * Convert a hyphenated string to camelCase. - */ - function hyphenToCamelCase(string) { - return string.replace(/-(.)/g, function(match, chr) { - return chr.toUpperCase(); - }); - } - - /** - * Determines if the specified string consists entirely of whitespace. - */ - function isEmpty(string) { - return !/[^\s]/.test(string); - } - - /** - * Determines if the specified string consists entirely of numeric characters. - */ - function isNumeric(input) { - return input !== undefined - && input !== null - && (typeof input === 'number' || parseInt(input, 10) == input); - } - - var HTMLtoJSX = function(config) { - this.config = config || {}; - - if (this.config.createClass === undefined) { - this.config.createClass = true; - } - if (!this.config.indent) { - this.config.indent = ' '; - } - if (!this.config.outputClassName) { - this.config.outputClassName = 'NewComponent'; - } - }; - HTMLtoJSX.prototype = { - /** - * Reset the internal state of the converter - */ - reset: function() { - this.output = ''; - this.level = 0; - }, - /** - * Main entry point to the converter. Given the specified HTML, returns a - * JSX object representing it. - * @param {string} html HTML to convert - * @return {string} JSX - */ - convert: function(html) { - this.reset(); - - // It turns out browsers have good HTML parsers (imagine that). - // Let's take advantage of it. - var containerEl = document.createElement('div'); - containerEl.innerHTML = '\n' + this._cleanInput(html) + '\n'; - - if (this.config.createClass) { - if (this.config.outputClassName) { - this.output = 'var ' + this.config.outputClassName + ' = React.createClass({\n'; - } else { - this.output = 'React.createClass({\n'; - } - this.output += this.config.indent + 'render: function() {' + "\n"; - this.output += this.config.indent + this.config.indent + 'return (\n'; - } - - if (this._onlyOneTopLevel(containerEl)) { - // Only one top-level element, the component can return it directly - // No need to actually visit the container element - this._traverse(containerEl); - } else { - // More than one top-level element, need to wrap the whole thing in a - // container. - this.output += this.config.indent + this.config.indent + this.config.indent; - this.level++; - this._visit(containerEl); - } - this.output = this.output.trim() + '\n'; - if (this.config.createClass) { - this.output += this.config.indent + this.config.indent + ');\n'; - this.output += this.config.indent + '}\n'; - this.output += '});'; - } - return this.output; - }, - - /** - * Cleans up the specified HTML so it's in a format acceptable for - * converting. - * - * @param {string} html HTML to clean - * @return {string} Cleaned HTML - */ - _cleanInput: function(html) { - // Remove unnecessary whitespace - html = html.trim(); - // Ugly method to strip script tags. They can wreak havoc on the DOM nodes - // so let's not even put them in the DOM. - html = html.replace(//g, ''); - return html; - }, - - /** - * Determines if there's only one top-level node in the DOM tree. That is, - * all the HTML is wrapped by a single HTML tag. - * - * @param {DOMElement} containerEl Container element - * @return {boolean} - */ - _onlyOneTopLevel: function(containerEl) { - // Only a single child element - if ( - containerEl.childNodes.length === 1 - && containerEl.childNodes[0].nodeType === NODE_TYPE.ELEMENT - ) { - return true; - } - // Only one element, and all other children are whitespace - var foundElement = false; - for (var i = 0, count = containerEl.childNodes.length; i < count; i++) { - var child = containerEl.childNodes[i]; - if (child.nodeType === NODE_TYPE.ELEMENT) { - if (foundElement) { - // Encountered an element after already encountering another one - // Therefore, more than one element at root level - return false; - } else { - foundElement = true; - } - } else if (child.nodeType === NODE_TYPE.TEXT && !isEmpty(child.textContent)) { - // Contains text content - return false; - } - } - return true; - }, - - /** - * Gets a newline followed by the correct indentation for the current - * nesting level - * - * @return {string} - */ - _getIndentedNewline: function() { - return '\n' + repeatString(this.config.indent, this.level + 2); - }, - - /** - * Handles processing the specified node - * - * @param {Node} node - */ - _visit: function(node) { - this._beginVisit(node); - this._traverse(node); - this._endVisit(node); - }, - - /** - * Traverses all the children of the specified node - * - * @param {Node} node - */ - _traverse: function(node) { - this.level++; - for (var i = 0, count = node.childNodes.length; i < count; i++) { - this._visit(node.childNodes[i]); - } - this.level--; - }, - - /** - * Handle pre-visit behaviour for the specified node. - * - * @param {Node} node - */ - _beginVisit: function(node) { - switch (node.nodeType) { - case NODE_TYPE.ELEMENT: - this._beginVisitElement(node); - break; - - case NODE_TYPE.TEXT: - this._visitText(node); - break; - - case NODE_TYPE.COMMENT: - this._visitComment(node); - break; - - default: - console.warn('Unrecognised node type: ' + node.nodeType); - } - }, - - /** - * Handles post-visit behaviour for the specified node. - * - * @param {Node} node - */ - _endVisit: function(node) { - switch (node.nodeType) { - case NODE_TYPE.ELEMENT: - this._endVisitElement(node); - break; - // No ending tags required for these types - case NODE_TYPE.TEXT: - case NODE_TYPE.COMMENT: - break; - } - }, - - /** - * Handles pre-visit behaviour for the specified element node - * - * @param {DOMElement} node - */ - _beginVisitElement: function(node) { - var tagName = node.tagName.toLowerCase(); - var attributes = []; - for (var i = 0, count = node.attributes.length; i < count; i++) { - attributes.push(this._getElementAttribute(node, node.attributes[i])); - } - - this.output += '<' + tagName; - if (attributes.length > 0) { - this.output += ' ' + attributes.join(' '); - } - if (node.firstChild) { - this.output += '>'; - } - }, - - /** - * Handles post-visit behaviour for the specified element node - * - * @param {Node} node - */ - _endVisitElement: function(node) { - // De-indent a bit - // TODO: It's inefficient to do it this way :/ - this.output = trimEnd(this.output, this.config.indent); - if (node.firstChild) { - this.output += ''; - } else { - this.output += ' />'; - } - }, - - /** - * Handles processing of the specified text node - * - * @param {TextNode} node - */ - _visitText: function(node) { - var text = node.textContent; - // If there's a newline in the text, adjust the indent level - if (text.indexOf('\n') > -1) { - text = node.textContent.replace(/\n\s*/g, this._getIndentedNewline()); - } - this.output += text; - }, - - /** - * Handles processing of the specified text node - * - * @param {Text} node - */ - _visitComment: function(node) { - // Do not render the comment - // Since we remove comments, we also need to remove the next line break so we - // don't end up with extra whitespace after every comment - //if (node.nextSibling && node.nextSibling.nodeType === NODE_TYPE.TEXT) { - // node.nextSibling.textContent = node.nextSibling.textContent.replace(/\n\s*/, ''); - //} - this.output += '{/*' + node.textContent.replace('*/', '* /') + '*/}'; - }, - - /** - * Gets a JSX formatted version of the specified attribute from the node - * - * @param {DOMElement} node - * @param {object} attribute - * @return {string} - */ - _getElementAttribute: function(node, attribute) { - switch (attribute.name) { - case 'style': - return this._getStyleAttribute(attribute.value); - default: - var name = ATTRIBUTE_MAPPING[attribute.name] || attribute.name; - var result = name + '='; - // Numeric values should be output as {123} not "123" - if (isNumeric(attribute.value)) { - result += '{' + attribute.value + '}'; - } else { - result += '"' + attribute.value.replace('"', '"') + '"'; - } - return result; - } - }, - - /** - * Gets a JSX formatted version of the specified element styles - * - * @param {string} styles - * @return {string} - */ - _getStyleAttribute: function(styles) { - var jsxStyles = new StyleParser(styles).toJSXString(); - return 'style={{' + jsxStyles + '}}'; - } - }; - - /** - * Handles parsing of inline styles - * - * @param {string} rawStyle Raw style attribute - * @constructor - */ - var StyleParser = function(rawStyle) { - this.parse(rawStyle); - }; - StyleParser.prototype = { - /** - * Parse the specified inline style attribute value - * @param {string} rawStyle Raw style attribute - */ - parse: function(rawStyle) { - this.styles = {}; - rawStyle.split(';').forEach(function(style) { - style = style.trim(); - var firstColon = style.indexOf(':'); - var key = style.substr(0, firstColon); - var value = style.substr(firstColon + 1).trim(); - if (key !== '') { - this.styles[key] = value; - } - }, this); - }, - - /** - * Convert the style information represented by this parser into a JSX - * string - * - * @return {string} - */ - toJSXString: function() { - var output = []; - for (var key in this.styles) { - if (!this.styles.hasOwnProperty(key)) { - continue; - } - output.push(this.toJSXKey(key) + ': ' + this.toJSXValue(this.styles[key])); - } - return output.join(', '); - }, - - /** - * Convert the CSS style key to a JSX style key - * - * @param {string} key CSS style key - * @return {string} JSX style key - */ - toJSXKey: function(key) { - return hyphenToCamelCase(key); - }, - - /** - * Convert the CSS style value to a JSX style value - * - * @param {string} value CSS style value - * @return {string} JSX style value - */ - toJSXValue: function(value) { - if (isNumeric(value)) { - // If numeric, no quotes - return value; - } else if (endsWith(value, 'px')) { - // "500px" -> 500 - return trimEnd(value, 'px'); - } else { - // Proably a string, wrap it in quotes - return '\'' + value.replace(/'/g, '"') + '\''; - } - } - }; - - // Expose public API - global.HTMLtoJSX = HTMLtoJSX; -}(window)); \ No newline at end of file +// Ideally it would be nice to just redirect, but Github Pages is very basic and +// lacks that functionality. +console.warn( + 'html-jsx-lib.js has moved to http://reactjs.github.io/react-magic/' + + 'htmltojsx.min.js. If using React-Magic, you are no longer required to ' + + 'link to this file. Please delete its