From ffa70704ca6d52a3012d54b46a8bcebe8ccd1f8a Mon Sep 17 00:00:00 2001 From: Steve Mao Date: Tue, 4 Oct 2016 22:12:12 +1100 Subject: [PATCH 01/97] simplify npm link script a little bit (#7862) We don't need to remove the folders before linking the modules --- docs/contributing/how-to-contribute.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/contributing/how-to-contribute.md b/docs/contributing/how-to-contribute.md index 1ec2fa27ab..fecb96ef73 100644 --- a/docs/contributing/how-to-contribute.md +++ b/docs/contributing/how-to-contribute.md @@ -116,8 +116,6 @@ If you want to try your changes in your existing React project, you may copy `bu ```sh cd your_project -rm -rf node_modules/react -rm -rf node_modules/react-dom npm link ~/path_to_your_react_clone/build/packages/react npm link ~/path_to_your_react_clone/build/packages/react-dom ``` From 1d099c001fac6bef5eac8b14e522c054624f448f Mon Sep 17 00:00:00 2001 From: KeicaM Date: Tue, 4 Oct 2016 13:19:44 +0200 Subject: [PATCH 02/97] Update 04-multiple-components.md (#7861) added missing map bracket --- docs/docs/04-multiple-components.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/04-multiple-components.md b/docs/docs/04-multiple-components.md index c74476779a..4813dea40d 100644 --- a/docs/docs/04-multiple-components.md +++ b/docs/docs/04-multiple-components.md @@ -138,7 +138,7 @@ class MyComponent extends React.Component { ); } @@ -157,7 +157,7 @@ class MyComponent extends React.Component { ); } From 75e912721631029be65383245d9d0d62bd23f696 Mon Sep 17 00:00:00 2001 From: Marcelo Alves Date: Mon, 3 Oct 2016 17:07:56 -0700 Subject: [PATCH 03/97] Fix minor typo in closing H1 tag (#7855) --- docs/docs/05-reusable-components.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/05-reusable-components.md b/docs/docs/05-reusable-components.md index c9d8ca3e2d..a427fa4845 100644 --- a/docs/docs/05-reusable-components.md +++ b/docs/docs/05-reusable-components.md @@ -201,7 +201,7 @@ Or using the new ES6 arrow syntax: ```javascript const Greeting = (props) => ( -

Hello, {props.name} +

Hello, {props.name}

); ReactDOM.render( @@ -217,7 +217,7 @@ However, you may still specify `.propTypes` and `.defaultProps` by setting them ```javascript function Greeting(props) { return ( -

Hello, {props.name} +

Hello, {props.name}

); } From 6ac0bbfd17f1541b3d0351d1c4a3fb02432ac80b Mon Sep 17 00:00:00 2001 From: ankitml Date: Tue, 24 May 2016 02:15:16 +0530 Subject: [PATCH 04/97] Use ES6 in Language Tooling doc --- docs/docs/09.1-language-tooling.md | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/docs/docs/09.1-language-tooling.md b/docs/docs/09.1-language-tooling.md index 79f24480f4..75c0c28cad 100644 --- a/docs/docs/09.1-language-tooling.md +++ b/docs/docs/09.1-language-tooling.md @@ -37,28 +37,23 @@ Example output: ``` $ cat test.js -var HelloMessage = React.createClass({ - render: function() { - return
Hello {this.props.name}
; - } -}); +function HelloMessage(props) { + return
Hello {props.name}
; +} ReactDOM.render(, mountNode); + $ babel test.js "use strict"; -var HelloMessage = React.createClass({ - displayName: "HelloMessage", - - render: function render() { - return React.createElement( - "div", - null, - "Hello ", - this.props.name - ); - } -}); +function HelloMessage(props) { + return React.createElement( + "div", + null, + "Hello ", + props.name + ); +} ReactDOM.render(React.createElement(HelloMessage, { name: "John" }), mountNode); ``` From 9a9a6cf10bf4b2c1d70503fd89e29031e2592559 Mon Sep 17 00:00:00 2001 From: Kateryna Date: Tue, 4 Oct 2016 20:43:49 +0300 Subject: [PATCH 05/97] Fix initial state example for Recat.createClass (#7867) In the example there was a typo with setting initial state using `getInitialState` method --- docs/docs/05-reusable-components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/05-reusable-components.md b/docs/docs/05-reusable-components.md index a427fa4845..118dafe8d8 100644 --- a/docs/docs/05-reusable-components.md +++ b/docs/docs/05-reusable-components.md @@ -324,7 +324,7 @@ With `React.createClass()`, you have to provide a separate `getInitialState` met ```javascript var Counter = React.createClass({ getInitialState: function() { - return {count: props.initialCount}; + return {count: this.props.initialCount}; }, // ... }); From 5fe354bc1e8e63c1257482fd89f10a8991883368 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Tue, 4 Oct 2016 19:33:09 +0100 Subject: [PATCH 06/97] Update the homepage with ES6 (#7868) * Update the homepage with ES6 * Avoid array spread and stale state --- README.md | 6 ++-- docs/Rakefile | 4 +-- docs/_js/examples/hello.js | 11 +++--- docs/_js/examples/markdown.js | 29 +++++++++------- docs/_js/examples/timer.js | 37 +++++++++++--------- docs/_js/examples/todo.js | 63 ++++++++++++++++++++++------------- docs/_js/live_editor.js | 20 +++++++---- docs/_layouts/default.html | 2 +- 8 files changed, 104 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index a2201bcf2b..c06f68f36b 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,11 @@ React is a JavaScript library for building user interfaces. We have several examples [on the website](https://facebook.github.io/react/). Here is the first one to get you started: ```js -var HelloMessage = React.createClass({ - render: function() { +class HelloMessage extends React.Component { + render() { return
Hello {this.props.name}
; } -}); +} ReactDOM.render( , diff --git a/docs/Rakefile b/docs/Rakefile index d50dc5b102..7a9872b7c0 100644 --- a/docs/Rakefile +++ b/docs/Rakefile @@ -6,8 +6,8 @@ require('open-uri') desc "download babel-browser" task :fetch_remotes do IO.copy_stream( - open('https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js'), - 'js/babel-browser.min.js' + open('https://unpkg.com/babel-standalone@6.15.0/babel.min.js'), + 'js/babel.min.js' ) end diff --git a/docs/_js/examples/hello.js b/docs/_js/examples/hello.js index bab86329c6..16f7f1a409 100644 --- a/docs/_js/examples/hello.js +++ b/docs/_js/examples/hello.js @@ -1,12 +1,13 @@ +var name = Math.random() > 0.5 ? 'Jane' : 'John'; var HELLO_COMPONENT = ` -var HelloMessage = React.createClass({ - render: function() { +class HelloMessage extends React.Component { + render() { return
Hello {this.props.name}
; } -}); +} -ReactDOM.render(, mountNode); -`; +ReactDOM.render(, mountNode); +`.trim(); ReactDOM.render( , diff --git a/docs/_js/examples/markdown.js b/docs/_js/examples/markdown.js index 8ec68ac670..696074cd65 100644 --- a/docs/_js/examples/markdown.js +++ b/docs/_js/examples/markdown.js @@ -1,16 +1,21 @@ var MARKDOWN_COMPONENT = ` -var MarkdownEditor = React.createClass({ - getInitialState: function() { - return {value: 'Type some *markdown* here!'}; - }, - handleChange: function() { +class MarkdownEditor extends React.Component { + constructor(props) { + super(props); + this.handleChange = this.handleChange.bind(this); + this.state = {value: 'Type some *markdown* here!'}; + } + + handleChange() { this.setState({value: this.refs.textarea.value}); - }, - rawMarkup: function() { + } + + getRawMarkup() { var md = new Remarkable(); return { __html: md.render(this.state.value) }; - }, - render: function() { + } + + render() { return (

Input

@@ -21,15 +26,15 @@ var MarkdownEditor = React.createClass({

Output

); } -}); +} ReactDOM.render(, mountNode); -`; +`.trim(); ReactDOM.render( , diff --git a/docs/_js/examples/timer.js b/docs/_js/examples/timer.js index af9ebbd8af..3d8cfc4c60 100644 --- a/docs/_js/examples/timer.js +++ b/docs/_js/examples/timer.js @@ -1,26 +1,33 @@ var TIMER_COMPONENT = ` -var Timer = React.createClass({ - getInitialState: function() { - return {secondsElapsed: 0}; - }, - tick: function() { - this.setState({secondsElapsed: this.state.secondsElapsed + 1}); - }, - componentDidMount: function() { - this.interval = setInterval(this.tick, 1000); - }, - componentWillUnmount: function() { +class Timer extends React.Component { + constructor(props) { + super(props); + this.state = {secondsElapsed: 0}; + } + + tick() { + this.setState((prevState) => ({ + secondsElapsed: prevState.secondsElapsed + 1 + })); + } + + componentDidMount() { + this.interval = setInterval(() => this.tick(), 1000); + } + + componentWillUnmount() { clearInterval(this.interval); - }, - render: function() { + } + + render() { return (
Seconds Elapsed: {this.state.secondsElapsed}
); } -}); +} ReactDOM.render(, mountNode); -`; +`.trim(); ReactDOM.render( , diff --git a/docs/_js/examples/todo.js b/docs/_js/examples/todo.js index cc7c979c30..eaac631dec 100644 --- a/docs/_js/examples/todo.js +++ b/docs/_js/examples/todo.js @@ -1,41 +1,56 @@ var TODO_COMPONENT = ` -var TodoList = React.createClass({ - render: function() { - var createItem = function(item) { - return
  • {item.text}
  • ; - }; - return
      {this.props.items.map(createItem)}
    ; +class TodoApp extends React.Component { + constructor(props) { + super(props); + this.handleChange = this.handleChange.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + this.state = {items: [], text: ''}; } -}); -var TodoApp = React.createClass({ - getInitialState: function() { - return {items: [], text: ''}; - }, - onChange: function(e) { - this.setState({text: e.target.value}); - }, - handleSubmit: function(e) { - e.preventDefault(); - var nextItems = this.state.items.concat([{text: this.state.text, id: Date.now()}]); - var nextText = ''; - this.setState({items: nextItems, text: nextText}); - }, - render: function() { + + render() { return (

    TODO

    - +
    ); } -}); + + handleChange(e) { + this.setState({text: e.target.value}); + } + + handleSubmit(e) { + e.preventDefault(); + var newItem = { + text: this.state.text, + id: Date.now() + }; + this.setState((prevState) => ({ + items: prevState.items.concat(newItem), + text: '' + })); + } +} + +class TodoList extends React.Component { + render() { + return ( +
      + {this.props.items.map(item => ( +
    • {item.text}
    • + ))} +
    + ); + } +} ReactDOM.render(, mountNode); -`; +`.trim(); ReactDOM.render( , diff --git a/docs/_js/live_editor.js b/docs/_js/live_editor.js index 27b4c81af1..134cae5b86 100644 --- a/docs/_js/live_editor.js +++ b/docs/_js/live_editor.js @@ -90,8 +90,14 @@ var ReactPlayground = React.createClass({ getDefaultProps: function() { return { - transformer: function(code) { - return babel.transform(code).code; + transformer: function(code, options) { + var presets = ['react']; + if (!options || !options.skipES2015Transform) { + presets.push('es2015'); + } + return Babel.transform(code, { + presets + }).code; }, editorTabTitle: 'Live JSX Editor', showCompiledJSTab: true, @@ -115,15 +121,15 @@ var ReactPlayground = React.createClass({ this.setState({mode: mode}); }, - compileCode: function() { - return this.props.transformer(this.state.code); + compileCode: function(options) { + return this.props.transformer(this.state.code, options); }, render: function() { var isJS = this.state.mode === this.MODES.JS; var compiledCode = ''; try { - compiledCode = this.compileCode(); + compiledCode = this.compileCode({skipES2015Transform: true}); } catch (err) {} var JSContent = @@ -201,13 +207,15 @@ var ReactPlayground = React.createClass({ } catch (e) { } try { - var compiledCode = this.compileCode(); + var compiledCode; if (this.props.renderCode) { + compiledCode = this.compileCode({skipES2015Transform: true}); ReactDOM.render( , mountNode ); } else { + compiledCode = this.compileCode({skipES2015Transform: false}); eval(compiledCode); } } catch (err) { diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index d42b8b1572..a3a44a53aa 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -36,7 +36,7 @@ - + From 1f605930cc393b90a2421479df5eee225235b1fe Mon Sep 17 00:00:00 2001 From: Michael O'Brien Date: Tue, 4 Oct 2016 22:53:26 +0100 Subject: [PATCH 07/97] Update comment to refer to correct method name (#7873) --- docs/docs/05-reusable-components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/05-reusable-components.md b/docs/docs/05-reusable-components.md index 118dafe8d8..513f37a78e 100644 --- a/docs/docs/05-reusable-components.md +++ b/docs/docs/05-reusable-components.md @@ -347,7 +347,7 @@ class SayHello extends React.Component { } render() { - // Because we `this.tick` is bound, we can use it as an event handler. + // Because `this.handleClick` is bound, we can use it as an event handler. return (
    `), or both. + +The DOM nodes produced by the child components will be appended to the parent DOM node, and recursively, the complete DOM structure will be assembled. + +>**Note:** +> +>The reconciler itself is not tied to the DOM. The exact result of mounting (sometimes called "mount image" in the source code) depends on the renderer, and can be a DOM node (React DOM), a string (React DOM Server), or a number representing a native view (React Native). + +If we were to extend the code to handle host elements, it would look like this: + +```js +function isClass(type) { + // React.Component subclasses have this flag + return ( + Boolean(type.prototype) && + Boolean(type.prototype.isReactComponent) + ); +} + +// This function only handles elements with a composite type. +// For example, it handles and - ); - } -} -``` - -With `React.createClass()`, this is not necessary because it binds all methods: - -```javascript -var SayHello = React.createClass({ - handleClick: function() { - alert('Hello!'); - }, - - render: function() { - return ( - - ); - } -}); -``` - -This means writing ES6 classes comes with a little more boilerplate code for event handlers, but the upside is slightly better performance in large applications. - -If the boilerplate code is too unattractive to you, you may enable the **experimental** [Class Properties](https://babeljs.io/docs/plugins/transform-class-properties/) syntax proposal with Babel: - - -```javascript -class SayHello extends React.Component { - // WARNING: this syntax is experimental! - // Using an arrow here binds the method: - handleClick = () => { - alert('Hello!'); - } - - render() { - return ( - - ); - } -} -``` - -Please note that the syntax above is **experimental** and the syntax may change, or the proposal might not make it into the language. - -If you'd rather play it safe, you have a few options: - -* Bind methods in the constructor. -* Use arrow functions, e.g. `onClick={(e) => this.handleClick(e)})`. -* Keep using `React.createClass()`. - -### Mixins - ->**Note:** -> ->ES6 launched without any mixin support. Therefore, there is no support for mixins when you use React with ES6 classes. -> ->**We also found numerous issues in codebases using mixins, [and don't recommend using them in the new code](/react/blog/2016/07/13/mixins-considered-harmful.html).** -> ->This section exists only for the reference. - -Sometimes very different components may share some common functionality. These are sometimes called [cross-cutting concerns](https://en.wikipedia.org/wiki/Cross-cutting_concern). [`React.createClass`](/react/docs/top-level-api.html#react.createclass) lets you use a legacy `mixins` system for that. - -One common use case is a component wanting to update itself on a time interval. It's easy to use `setInterval()`, but it's important to cancel your interval when you don't need it anymore to save memory. React provides [lifecycle methods](/react/docs/working-with-the-browser.html#component-lifecycle) that let you know when a component is about to be created or destroyed. Let's create a simple mixin that uses these methods to provide an easy `setInterval()` function that will automatically get cleaned up when your component is destroyed. - -```javascript -var SetIntervalMixin = { - componentWillMount: function() { - this.intervals = []; - }, - setInterval: function() { - this.intervals.push(setInterval.apply(null, arguments)); - }, - componentWillUnmount: function() { - this.intervals.forEach(clearInterval); - } -}; - -var TickTock = React.createClass({ - mixins: [SetIntervalMixin], // Use the mixin - getInitialState: function() { - return {seconds: 0}; - }, - componentDidMount: function() { - this.setInterval(this.tick, 1000); // Call a method on the mixin - }, - tick: function() { - this.setState({seconds: this.state.seconds + 1}); - }, - render: function() { - return ( -

    - React has been running for {this.state.seconds} seconds. -

    - ); - } -}); - -ReactDOM.render( - , - document.getElementById('example') -); -``` - -If a component is using multiple mixins and several mixins define the same lifecycle method (i.e. several mixins want to do some cleanup when the component is destroyed), all of the lifecycle methods are guaranteed to be called. Methods defined on mixins run in the order mixins were listed, followed by a method call on the component. diff --git a/docs/docs/05-reusable-components.zh-CN.md b/docs/docs/05-reusable-components.zh-CN.md deleted file mode 100644 index 8c31b75a99..0000000000 --- a/docs/docs/05-reusable-components.zh-CN.md +++ /dev/null @@ -1,285 +0,0 @@ ---- -id: reusable-components-zh-CN -title: 可复用组件 -permalink: docs/reusable-components-zh-CN.html -prev: multiple-components-zh-CN.html -next: transferring-props-zh-CN.html ---- - -设计接口的时候,把通用的设计元素(按钮,表单框,布局组件等)拆成接口良好定义的可复用的组件。这样,下次开发相同界面程序时就可以写更少的代码,也意义着更高的开发效率,更少的 Bug 和更少的程序体积。 - -## Prop 验证 - -随着应用不断变大,保证组件被正确使用变得非常有用。为此我们引入 `propTypes`。`React.PropTypes` 提供很多验证器 (validator) 来验证传入数据的有效性。当向 props 传入无效数据时,JavaScript 控制台会抛出警告。注意为了性能考虑,只在开发环境验证 `propTypes`。下面用例子来说明不同验证器的区别: - -```javascript -React.createClass({ - propTypes: { - // 可以声明 prop 为指定的 JS 基本类型。默认 - // 情况下,这些 prop 都是可传可不传的。 - optionalArray: React.PropTypes.array, - optionalBool: React.PropTypes.bool, - optionalFunc: React.PropTypes.func, - optionalNumber: React.PropTypes.number, - optionalObject: React.PropTypes.object, - optionalString: React.PropTypes.string, - optionalSymbol: React.PropTypes.symbol, - - // 所有可以被渲染的对象:数字, - // 字符串,DOM 元素或包含这些类型的数组(or fragment) 。 - optionalNode: React.PropTypes.node, - - // React 元素 - optionalElement: React.PropTypes.element, - - // 你同样可以断言一个 prop 是一个类的实例。 - // 用 JS 的 instanceof 操作符声明 prop 为类的实例。 - optionalMessage: React.PropTypes.instanceOf(Message), - - // 你可以用 enum 的方式 - // 确保你的 prop 被限定为指定值。 - optionalEnum: React.PropTypes.oneOf(['News', 'Photos']), - - // 指定的多个对象类型中的一个 - optionalUnion: React.PropTypes.oneOfType([ - React.PropTypes.string, - React.PropTypes.number, - React.PropTypes.instanceOf(Message) - ]), - - // 指定类型组成的数组 - optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number), - - // 指定类型的属性构成的对象 - optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number), - - // 特定形状参数的对象 - optionalObjectWithShape: React.PropTypes.shape({ - color: React.PropTypes.string, - fontSize: React.PropTypes.number - }), - - // 你可以在任意东西后面加上 `isRequired` - // 来确保 如果 prop 没有提供 就会显示一个警告。 - requiredFunc: React.PropTypes.func.isRequired, - - // 不可空的任意类型 - requiredAny: React.PropTypes.any.isRequired, - - // 你可以自定义一个验证器。如果验证失败需要返回一个 Error 对象。 - // 不要直接使用 `console.warn` 或抛异常, - // 因为这在 `oneOfType` 里不起作用。 - customProp: function(props, propName, componentName) { - if (!/matchme/.test(props[propName])) { - return new Error('Validation failed!'); - } - } - }, - /* ... */ -}); -``` - -### Single Child - -用 `React.PropTypes.element` 你可以指定仅有一个子级能被传送给组件 - -```javascript -var MyComponent = React.createClass({ - propTypes: { - children: React.PropTypes.element.isRequired - }, - - render: function() { - return ( -
    - {this.props.children} // 这里必须是一个元素否则就会警告 -
    - ); - } - -}); -``` - -## 默认 Prop 值 - -React 支持以声明式的方式来定义 `props` 的默认值。 - -```javascript -var ComponentWithDefaultProps = React.createClass({ - getDefaultProps: function() { - return { - value: 'default value' - }; - } - /* ... */ -}); -``` - -当父级没有传入 props 时,`getDefaultProps()` 可以保证 `this.props.value` 有默认值,注意 `getDefaultProps` 的结果会被 *缓存*。得益于此,你可以直接使用 props,而不必写手动编写一些重复或无意义的代码。 - -## 传递 Props:捷径 - -有一些常用的 React 组件只是对 HTML 做简单扩展。通常,你想复制任何传进你的组件的HTML属性到底层的HTML元素上。为了减少输入,你可以用 JSX _spread_ 语法来完成: - -```javascript -var CheckLink = React.createClass({ - render: function() { - // 这样会把 CheckList 所有的 props 复制到 - return {'√ '}{this.props.children}; - } -}); - -ReactDOM.render( - - Click here! - , - document.getElementById('example') -); -``` - -## Mixins - -组件是 React 里复用代码的最佳方式,但是有时一些不同的组件间也需要共用一些功能。有时会被称为 [跨切面关注点](https://en.wikipedia.org/wiki/Cross-cutting_concern)。React 使用 `mixins` 来解决这类问题。 - -一个通用的场景是:一个组件需要定期更新。用 `setInterval()` 做很容易,但当不需要它的时候取消定时器来节省内存是非常重要的。React 提供 [生命周期方法](/react/docs/working-with-the-browser.html#component-lifecycle) 来告知你组件创建或销毁的时间。下面来做一个简单的 mixin,使用 `setInterval()` 并保证在组件销毁时清理定时器。 - -```javascript -var SetIntervalMixin = { - componentWillMount: function() { - this.intervals = []; - }, - setInterval: function() { - this.intervals.push(setInterval.apply(null, arguments)); - }, - componentWillUnmount: function() { - this.intervals.forEach(clearInterval); - } -}; - -var TickTock = React.createClass({ - mixins: [SetIntervalMixin], // 引用 mixin - getInitialState: function() { - return {seconds: 0}; - }, - componentDidMount: function() { - this.setInterval(this.tick, 1000); // 调用 mixin 的方法 - }, - tick: function() { - this.setState({seconds: this.state.seconds + 1}); - }, - render: function() { - return ( -

    - React has been running for {this.state.seconds} seconds. -

    - ); - } -}); - -ReactDOM.render( - , - document.getElementById('example') -); -``` - -关于 mixin 值得一提的优点是,如果一个组件使用了多个 mixin,并用有多个 mixin 定义了同样的生命周期方法(如:多个 mixin 都需要在组件销毁时做资源清理操作),所有这些生命周期方法都保证会被执行到。方法执行顺序是:首先按 mixin 引入顺序执行 mixin 里方法,最后执行组件内定义的方法。 - -## ES6 Classes - -你也可以以一个简单的 JavaScript 类来定义你的React classes。使用ES6 class的例子: - -```javascript -class HelloMessage extends React.Component { - render() { - return
    Hello {this.props.name}
    ; - } -} -ReactDOM.render(, mountNode); -``` - -API近似于 `React.createClass` 除了 `getInitialState`。 你应该在构造函数里设置你的`state`,而不是提供一个单独的 `getInitialState` 方法。就像 `getInitialState` 的返回值,你赋给 `this.state` 的值会被作为组件的初始 state。 - -另一个不同是 `propTypes` 和 `defaultProps` 是在构造函数里被定义为属性,而不是在 class body 里。 - -```javascript -export class Counter extends React.Component { - constructor(props) { - super(props); - this.state = {count: props.initialCount}; - } - tick() { - this.setState({count: this.state.count + 1}); - } - render() { - return ( -
    - Clicks: {this.state.count} -
    - ); - } -} -Counter.propTypes = { initialCount: React.PropTypes.number }; -Counter.defaultProps = { initialCount: 0 }; -``` - -### 无自动绑定 - -方法遵循正式的ES6 class的语义,意味着它们不会自动绑定`this`到实例上。你必须显示的使用`.bind(this)` or [箭头函数](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions) `=>`: - -```javascript -// 你可以使用 bind() 来绑定 `this` -
    - -// 或者你可以使用箭头函数 -
    this.tick()}> -``` - -我们建议你在构造函数中绑定事件处理器,这样对于所有实例它们只需绑定一次: - -```javascript -constructor(props) { - super(props); - this.state = {count: props.initialCount}; - this.tick = this.tick.bind(this); -} -``` - -现在你可以直接使用 `this.tick` 因为它已经在构造函数里绑定过一次了。 - -```javascript -// 它已经在构造函数里绑定过了 -
    -``` - -这对应用的性能有帮助,特别是当你用 [浅层比较](/react/docs/shallow-compare.html) 实现 [shouldComponentUpdate()](/react/docs/component-specs.html#updating-shouldcomponentupdate) 时。 - -### 没有 Mixins - -不幸的是ES6的发布没有任何mixin的支持。因此,当你在ES6 classes下使用React时不支持mixins。作为替代,我们正在努力使它更容易不依靠mixins支持这些用例。 - -## 无状态函数 - -你也可以用 JavaScript 函数来定义你的 React 类。例如使用无状态函数语法: - -```javascript -function HelloMessage(props) { - return
    Hello {props.name}
    ; -} -ReactDOM.render(, mountNode); -``` - -或者使用新的ES6箭头函数: - -```javascript -const HelloMessage = (props) =>
    Hello {props.name}
    ; -ReactDOM.render(, mountNode); -``` - -这个简化的组件API旨在用于那些纯函数态的组件 。这些组件必须没有保持任何内部状态,没有备份实例,也没有组件生命周期方法。他们纯粹的函数式的转化他们的输入,没有引用。 -然而,你仍然可以以设置函数 properties 的方式来指定 `.propTypes` 和 `.defaultProps`,就像你在ES6类里设置他们那样。 - -> 注意: -> -> 因为无状态函数没有备份实例,你不能附加一个引用到一个无状态函数组件。 通常这不是问题,因为无状态函数不提供一个命令式的API。没有命令式的API,你就没有任何需要实例来做的事。然而,如果用户想查找无状态函数组件的DOM节点,他们必须把这个组件包装在一个有状态组件里(比如,ES6 类组件) 并且连接一个引用到有状态的包装组件。 - -在理想世界里,你的大多数组件都应该是无状态函数,因为将来我们可能会用避免不必要的检查和内存分配的方式来对这些组件进行优化。 如果可能,这是推荐的模式。 diff --git a/docs/docs/06-transferring-props.it-IT.md b/docs/docs/06-transferring-props.it-IT.md deleted file mode 100644 index 0eda8733c1..0000000000 --- a/docs/docs/06-transferring-props.it-IT.md +++ /dev/null @@ -1,153 +0,0 @@ ---- -id: transferring-props-it-IT -title: Trasferimento delle Proprietà -permalink: docs/transferring-props-it-IT.html -prev: reusable-components-it-IT.html -next: forms-it-IT.html ---- - -Un pattern comune in React è l'uso di un'astrazione per esporre un componente. Il componente esterno espone una semplice proprietà per effettuare un'azione che può richiedere un'implementazione più complessa. - -Puoi usare gli [attributi spread di JSX](/react/docs/jsx-spread.html) per unire le vecchie props con valori aggiuntivi: - -```javascript - -``` - -Se non usi JSX, puoi usare qualsiasi helper come l'API `Object.assign` di ES6, o il metodo `_.extend` di Underscore: - -```javascript -React.createElement(Component, Object.assign({}, this.props, { more: 'values' })); -``` - -Nel resto di questo tutorial vengono illustrate le best practices, usando JSX e sintassi sperimentale di ES7. - -## Trasferimento Manuale - -Nella maggior parte dei casi dovresti esplicitamente passare le proprietà. Ciò assicura che venga esposto soltanto un sottoinsieme dell'API interna, del cui funzionamento si è certi. - -```javascript -function FancyCheckbox(props) { - var fancyClass = props.checked ? 'FancyChecked' : 'FancyUnchecked'; - return ( -
    - {props.children} -
    - ); -} -ReactDOM.render( - - Ciao mondo! - , - document.getElementById('example') -); -``` - -E se aggiungessimo una proprietà `name`? O una proprietà `title`? O `onMouseOver`? - -## Trasferire con `...` in JSX - -> NOTA: -> -> La sintassi `...` fa parte della proposta Object Rest Spread. Questa proposta è in processo di diventare uno standard. Consulta la sezione [Proprietà Rest e Spread ...](/react/docs/transferring-props.html#rest-and-spread-properties-...) di seguito per maggiori dettagli. - -A volte passare manualmente ciascuna proprietà può essere noioso e fragile. In quei casi puoi usare l'[assegnamento destrutturante](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) con le proprietà residue per estrarre un insieme di proprietà sconosciute. - -Elenca tutte le proprietà che desideri consumare, seguite da `...other`. - -```javascript -var { checked, ...other } = props; -``` - -Ciò assicura che vengano passate tutte le proprietà TRANNE quelle che stai consumando tu stesso. - -```javascript -function FancyCheckbox(props) { - var { checked, ...other } = props; - var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked'; - // `other` contiene { onClick: console.log } ma non la proprietà checked - return ( -
    - ); -} -ReactDOM.render( - - Ciao mondo! - , - document.getElementById('example') -); -``` - -> NOTA: -> -> Nell'esempio precedente, la proprietà `checked` è anche un attributo DOM valido. Se non utilizzassi la destrutturazione in questo modo, potresti inavvertitamente assegnarlo al `div`. - -Usa sempre il pattern di destrutturazione quando trasferisci altre proprietà sconosciute in `other`. - -```javascript -function FancyCheckbox(props) { - var fancyClass = props.checked ? 'FancyChecked' : 'FancyUnchecked'; - // ANTI-PATTERN: `checked` sarebbe passato al componente interno - return ( -
    - ); -} -``` - -## Consumare e Trasferire la Stessa Proprietà - -Se il tuo componente desidera consumare una proprietà, ma anche passarla ad altri, puoi passarla esplicitamente mediante `checked={checked}`. Questo è preferibile a passare l'intero oggetto `this.props` dal momento che è più facile effettuarne il linting e il refactoring. - -```javascript -function FancyCheckbox(props) { - var { checked, title, ...other } = props; - var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked'; - var fancyTitle = checked ? 'X ' + title : 'O ' + title; - return ( - - ); -} -``` - -> NOTA: -> -> L'ordine è importante. Mettendo il `{...other}` prima delle tue proprietà JSX ti assicuri che il consumatore del tuo componente non possa ridefinirle. Nell'esempio precedente, abbiamo garantito che l'elemento input sarà del tipo `"checkbox"`. - -## Proprietà Rest e Spread `...` - -Le proprietà Rest ti permettono di estrarre le proprietà residue di un oggetto in un nuovo oggetto. Vengono escluse tutte le altre proprietà elencate nel pattern di destrutturazione. - -Questa è un'implementazione sperimentale di una [proposta ES7](https://github.com/sebmarkbage/ecmascript-rest-spread). - -```javascript -var { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; -x; // 1 -y; // 2 -z; // { a: 3, b: 4 } -``` - -> Nota: -> -> Questa proposta ha raggiunto lo stadio 2 ed è attivata in modo predefinito in Babel. Vecchie versioni di Babel potrebbero richiedere l'abilitazione esplicita di questa trasformazione con `babel --optional es7.objectRestSpread` - -## Trasferire con Underscore - -Se non usi JSX, puoi usare una libreria per ottenere il medesimo pattern. Underscore supporta `_.omit` per omettere delle proprietà ed `_.extend` per copiare le proprietà in un nuovo oggetto. - -```javascript -function FancyCheckbox(props) { - var checked = props.checked; - var other = _.omit(props, 'checked'); - var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked'; - return ( - React.DOM.div(_.extend({}, other, { className: fancyClass })) - ); -} -``` diff --git a/docs/docs/06-transferring-props.ja-JP.md b/docs/docs/06-transferring-props.ja-JP.md deleted file mode 100644 index 3ea4055d63..0000000000 --- a/docs/docs/06-transferring-props.ja-JP.md +++ /dev/null @@ -1,151 +0,0 @@ ---- -id: transferring-props -title: propsの移譲 -permalink: docs/transferring-props-ja-JP.html -prev: reusable-components-ja-JP.html -next: forms-ja-JP.html - ---- - - -コンポーネントを抽象的にラップすることはReactにおいて共通のパターンです。外のコンポーネントは単純なプロパティを表示し、中ではさらに複雑なインプリメンテーションの詳細を持つようになっています。 - -以下のように、古いpropsと追加の値を[JSXの拡張属性](/react/docs/jsx-spread-ja-JP.html)を使ってマージすることができます。 - -```javascript - -``` - -JSXを使わない場合は、以下のように、ES6の `Object.assign` か Underscore の `_.extend` といったオブジェクトヘルパーを使うことができます。 - -```javascript -React.createElement(Component, Object.assign({}, this.props, { more: 'values' })); -``` - -以下のチュートリアルはベストプラクティスを提示しています。JSXや試験的なES7のシンタックスを使っています。 - -## 手動での移動 - -ほとんどの場合、プロパティを明確に子要素に渡すべきです。それは、内部のAPIのサブセットだけを外に出していることと、認識しているプロパティが動作することを保証します。 - -```javascript -function FancyCheckbox(props) { - var fancyClass = props.checked ? 'FancyChecked' : 'FancyUnchecked'; - return ( -
    - {props.children} -
    - ); -} -ReactDOM.render( - - Hello world! - , - document.getElementById('example') -); -``` - -しかし、 `name` プロパティや `title` プロパティや `onMouseOver` はどうでしょうか? - -## JSXにおける `...` を使った移譲 - -> 注意: -> 以下の例では、実験的なES7のシンタックスであることを示すために `--harmony ` フラグが必要になります。ブラウザ上でJSXトランスフォーマーを使う際には、単純に ` - - -``` - -## Using React from Bower - -Bower is a package manager optimized for the front-end development. If multiple packages depend on a package - jQuery for example - Bower will download jQuery just once. This is known as a flat dependency graph and it helps reduce page load. For more info, visit [http://bower.io/](http://bower.io/). - -If you'd like to use bower, it's as easy as: - -``` -bower install --save react -``` - -```html - - - - - Hello React! - - - - - -
    - - - -``` - - -## Using master - -We have instructions for building from `master` [in our GitHub repository](https://github.com/facebook/react). diff --git a/docs/docs/09.3-environments.md b/docs/docs/09.3-environments.md deleted file mode 100644 index eb3f91d875..0000000000 --- a/docs/docs/09.3-environments.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -id: environments -title: Server-side Environments -permalink: docs/environments.html -prev: package-management.html -next: addons.html ---- - -One of the great things about React is that it doesn't require the DOM as a dependency, which means it is possible to render a React application on the server and send the HTML markup down to the client. There are a few things that React expects, so this guide will help you get started in your preferred environment. - - -## Node.js - -[Node.js](http://nodejs.org/) is a popular JavaScript runtime that comes with an extensive core library and support for installing packages from npm to expand on the basic functionality. As we've described elsewhere in the documentation, you can install `react` and `react-dom` from npm. - -Example: - -```js -var React = require('react'); -var ReactDOMServer = require('react-dom/server'); - -var element = React.createElement('div', null, 'Hello World!'); -console.log(ReactDOMServer.renderToString(element)); -``` - -If you use JSX, you may want to pre-compile your components. Alternatively you may want to consider using [Babel's require hook](https://babeljs.io/docs/usage/require/) or [`babel-node`](https://babeljs.io/docs/usage/cli/#babel-node). - -> Note: -> -> Some versions of Node.js have an `Object.assign` implementation that does not preserve key order. This can cause errors when validating the markup, creating a warning that says "React attempted to reuse markup in a container but the checksum was invalid". If you run into this issue, you can override `Object.assign` to use a polyfill that preserves key order. For more details, see [Issue #6451](https://github.com/facebook/react/issues/6451). - -C# -== - -Support for server-side component rendering and JSX compilation (via Babel) in a .NET Framework / ASP.NET environment is provided through our [ReactJS.NET](http://reactjs.net/) project. - - -## Nashorn - -Nashorn is a lightweight high-performance JavaScript runtime that runs within the JVM. React should run out of the box in Java 8+. - -Example: - -```java -import java.io.IOException; -import java.io.InputStream; -import java.io.FileReader; - -import javax.script.ScriptEngine; -import javax.script.ScriptEngineManager; -import javax.script.ScriptException; - -public class ReactRender -{ - public static void main(String[] args) throws ScriptException, IOException { - ScriptEngine nashorn = new ScriptEngineManager().getEngineByName("nashorn"); - - // These files can be downloaded as a part of the starter kit - // from https://facebook.github.io/react - nashorn.eval(new FileReader("path/to/react.js")); - nashorn.eval(new FileReader("path/to/react-dom-server.js")); - - System.out.println(nashorn.eval( - "ReactDOMServer.renderToString(" + - "React.createElement('div', null, 'Hello World!')" + - ");" - )); - } -} -``` - -If your application uses npm packages, or you want to transform JSX in Nashorn, you will need to do some additional environment setup. The following resources may be helpful in getting you started: - - * [http://winterbe.com/posts/2015/02/16/isomorphic-react-webapps-on-the-jvm/](http://winterbe.com/posts/2015/02/16/isomorphic-react-webapps-on-the-jvm/) - * [https://github.com/nodyn/jvm-npm](https://github.com/nodyn/jvm-npm) - * [https://gist.github.com/aesteve/883e0fd33390451cb8eb](https://gist.github.com/aesteve/883e0fd33390451cb8eb) - -> Note: -> -> Using Babel within Nashorn will require Java 8u72+, as update 72 fixed [JDK-8135190](https://bugs.openjdk.java.net/browse/JDK-8135190). diff --git a/docs/docs/10-addons.it-IT.md b/docs/docs/10-addons.it-IT.md deleted file mode 100644 index abbb3d4884..0000000000 --- a/docs/docs/10-addons.it-IT.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -id: addons-it-IT -title: Add-ons -permalink: docs/addons-it-IT.html -prev: tooling-integration-it-IT.html -next: animation-it-IT.html ---- - -`React.addons` è il luogo in cui parcheggiamo utili strumenti per costruire applicazioni React. **Questi strumenti devono essere considerati sperimentali** ma saranno eventualmente inclusi nel nucleo o una libreria ufficiale di utilities: - -- [`TransitionGroup` e `CSSTransitionGroup`](animation-it-IT.html), per gestire animazioni e transizioni che sono solitamente difficili da implementare, come ad esempio prima della rimozione di un componente. -- [`LinkedStateMixin`](two-way-binding-helpers-it-IT.html), per semplificare la coordinazione tra lo stato del componente e l'input dell'utente in un modulo. -- [`cloneWithProps`](clone-with-props-it-IT.html), per eseguire una copia superficiale di componenti React e cambiare le loro proprietà. -- [`createFragment`](create-fragment-it-IT.html), per creare un insieme di figli con chiavi esterne. -- [`update`](update-it-IT.html), una funzione di utilità che semplifica la gestione di dati immutabili in JavaScript. -- [`PureRenderMixin`](pure-render-mixin-it-IT.html), un aiuto per incrementare le prestazioni in certe situazioni. - -Gli add-ons elencati di seguito si trovano esclusivamente nella versione di sviluppo (non minificata) di React: - -- [`TestUtils`](test-utils-it-IT.html), semplici helper per scrivere dei test case (soltanto nella build non minificata). -- [`Perf`](perf-it-IT.html), per misurare le prestazioni e fornirti suggerimenti per l'ottimizzazione. - -Per ottenere gli add-on, usa `react-with-addons.js` (e la sua controparte non minificata) anziché il solito `react.js`. - -Quandi si usa il pacchetto react di npm, richiedi semplicemente `require('react/addons')` anziché `require('react')` per ottenere React con tutti gli add-on. diff --git a/docs/docs/10-addons.ja-JP.md b/docs/docs/10-addons.ja-JP.md deleted file mode 100644 index 9733aa25bb..0000000000 --- a/docs/docs/10-addons.ja-JP.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -id: addons -title: アドオン -permalink: docs/addons-ja-JP.html -prev: tooling-integration-ja-JP.html -next: animation-ja-JP.html ---- - -`React.addons` はReactのアプリケーションを作成する上で便利なユーティリティを置いておくための場所です。 **それらは実験的なものであると考えられるべきです。** しかし、ゆくゆくはコアに入ってくるか、以下のような承認されたユーティリティとなるでしょう。 - -- アニメーションや推移を扱う[`TransitionGroup` や `CSSTransitionGroup`](animation-ja-JP.html)は多くの場合実行するのが簡単ではありません。例えば、コンポーネントの削除の前などは。 -- [`LinkedStateMixin`](two-way-binding-helpers-ja-JP.html)はユーザのフォームの入力データとコンポーネントのstateの間の調整を単純化します。 -- [`cloneWithProps`](clone-with-props-ja-JP.html)はReactのコンポーネントのシャローコピーを作成したり、それらのpropsを変更したりします。 -- [`createFragment`](create-fragment-ja-JP.html)は外部のキー化された子要素のセットを作成します。 -- [`update`](update-ja-JP.html)はJavaScriptでイミュータブルなデータを扱うことを簡単にするヘルパーの関数です。 -- [`PureRenderMixin`](pure-render-mixin-ja-JP.html)は特定のシチュエーションでパフォーマンスを改善します。 -以下のアドオンはReactだけの開発版(縮小されていない版)です。 - -- [`TestUtils`](test-utils-ja-JP.html)はテストケースを記述する単純なヘルパーです(縮小されていないビルドのみ)。 -- [`Perf`](perf-ja-JP.html)はパフォーマンスを測り、どこを最適化するかのヒントを与えます。 - -アドオンを使うには、共通の `react.js` を使うよりも `react-with-addons.js` (とその縮小されたもの)を使ってください。 - -npmからReactのパッケージを使う際には、Reactと全てのアドオンを使うために `require('react')` を使う代わりに、単純に `require('react/addons')` を使ってください。 diff --git a/docs/docs/10-addons.ko-KR.md b/docs/docs/10-addons.ko-KR.md deleted file mode 100644 index 2a7059994b..0000000000 --- a/docs/docs/10-addons.ko-KR.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -id: addons-ko-KR -title: 애드온 -permalink: docs/addons-ko-KR.html -prev: tooling-integration-ko-KR.html -next: animation-ko-KR.html ---- - -React 애드온은 React 앱을 만드는 데 유용한 유틸리티의 모음입니다. **실험적인 기능으로 취급해야 하고** 코어보다 더 자주 변경될 수 있습니다. - -- [`TransitionGroup` 과 `CSSTransitionGroup`](animation-ko-KR.html)은 예를 들면 컴포넌트 삭제 직전의 트랜지션 처럼, 구현하기 까다로운 애니메이션과 트랜지션을 다룹니다. -- [`LinkedStateMixin`](two-way-binding-helpers-ko-KR.html)는 사용자 입력과 컴포넌트의 state사이의 조정(coordination)을 단순화 합니다. -- [`cloneWithProps`](clone-with-props-ko-KR.html)는 React 컴포넌트를 얕은 복사를 하고 props를 변경합니다. -- [`createFragment`](create-fragment-ko-KR.html)는 외부에서 키가 할당된 자식들의 모음을 만듭니다. -- [`update`](update-ko-KR.html)는 JavaScript안에서 불변 데이터를 다루기 쉽게하는 헬퍼 함수입니다. -- [`PureRenderMixin`](pure-render-mixin-ko-KR.html)는 특정 상황에서 성능을 향상시켜 줍니다. - -밑에 있는 애드온은 React 개발 (압축되지 않은) 버전에서만 사용가능 합니다. - -- [`TestUtils`](test-utils-ko-KR.html)는 테스트 케이스를 적기 위한 간단한 헬퍼입니다. (압축되지 않은 빌드에서만 사용가능) -- [`Perf`](perf-ko-KR.html)는 성능을 측정하고, 최적화를 위한 힌트를 제공합니다. - -애드온을 쓰려면, npm에서 각각 설치하세요.(예를 들면, `npm install react-addons-pure-render-mixin`) npm을 사용하지 않는 애드온 사용법에 대한 지원은 없습니다. diff --git a/docs/docs/10-addons.md b/docs/docs/10-addons.md deleted file mode 100644 index 9fa7b56dbc..0000000000 --- a/docs/docs/10-addons.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -id: addons -title: Add-ons -permalink: docs/addons.html -prev: environments.html -next: animation.html ---- - -The React add-ons are a collection of useful utility modules for building React apps. **These should be considered experimental** and tend to change more often than the core. - -- [`TransitionGroup` and `CSSTransitionGroup`](animation.html), for dealing with animations and transitions that are usually not simple to implement, such as before a component's removal. -- [`LinkedStateMixin`](two-way-binding-helpers.html), to simplify the coordination between user's form input data and the component's state. -- [`cloneWithProps`](clone-with-props.html), to make shallow copies of React components and change their props. -- [`createFragment`](create-fragment.html), to create a set of externally-keyed children. -- [`update`](update.html), a helper function that makes dealing with immutable data in JavaScript easier. -- [`PureRenderMixin`](pure-render-mixin.html), a performance booster under certain situations. -- [`shallowCompare`](shallow-compare.html), a helper function that performs a shallow comparison for props and state in a component to decide if a component should update. - -The add-ons below are in the development (unminified) version of React only: - -- [`TestUtils`](test-utils.html), simple helpers for writing test cases. -- [`Perf`](perf.html), a performance profiling tool for finding optimization opportunities. - -To get the add-ons, install them individually from npm (e.g., `npm install react-addons-pure-render-mixin`). We don't support using the addons if you're not using npm. diff --git a/docs/docs/10-addons.zh-CN.md b/docs/docs/10-addons.zh-CN.md deleted file mode 100644 index e9392b7baa..0000000000 --- a/docs/docs/10-addons.zh-CN.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -id: addons-zh-CN -title: 插件 -permalink: docs/addons-zh-CN.html -prev: tooling-integration-zh-CN.html -next: animation-zh-CN.html ---- - -React插件是一系列的用来构建 React app的有用模块。 **这些应该被认为是实验性的** 并趋向于比core变动更频繁。 - -- [`TransitionGroup` 和 `CSSTransitionGroup`](animation.html), 用来处理通常不能简单实现的动画和转换,比如在组件移除之前。 -- [`LinkedStateMixin`](two-way-binding-helpers.html), 简化用户的表单输入数据与组件状态的协调。 -- [`cloneWithProps`](clone-with-props.html), 创建React组件的浅拷贝并改变它们的props。 -- [`createFragment`](create-fragment.html), 创建一组外键的子级。 -- [`update`](update.html), 一个使不可变数据在JavaScript里更易处理的辅助函数。 -- [`PureRenderMixin`](pure-render-mixin.html), 一个特定情况下的性能优化器。 -- [`shallowCompare`](shallow-compare.html), 一个辅助函数,用来对 props 和 state在组件里 执行浅比较 以决定一个组件是否应该更新。 - -下面的插件只存在开发版(未压缩)React中: - -- [`TestUtils`](test-utils.html), 用于写测试用例的简单的辅助工具。 -- [`Perf`](perf.html), 一个用于查找优化机会的性能分析工具。 - -要获取插件,单独从npm安装他们(例如 `npm install react-addons-pure-render-mixin`).我们不支持使用插件如果你没有用npm. diff --git a/docs/docs/10.1-animation.it-IT.md b/docs/docs/10.1-animation.it-IT.md deleted file mode 100644 index 7f83da965d..0000000000 --- a/docs/docs/10.1-animation.it-IT.md +++ /dev/null @@ -1,261 +0,0 @@ ---- -id: animation-it-IT -title: Animazioni -permalink: docs/animation-it-IT.html -prev: addons-it-IT.html -next: two-way-binding-helpers-it-IT.html ---- - -React offre un componente addon `ReactTransitionGroup` come una API di basso livello per le animazioni, e un `ReactCSSTransitionGroup` per implementare facilmente animazioni e transizioni CSS di base. - -## API di Alto Livello: `ReactCSSTransitionGroup` - -`ReactCSSTransitionGroup` è basato su `ReactTransitionGroup` ed è una maniera semplice di effettuare transizioni e animazioni CSS quando un componente React viene aggiunto o rimosso dal DOM. È ispirato all'eccellente libreria [ng-animate](http://www.nganimate.org/). - -### Per Cominciare - -`ReactCSSTransitionGroup` è l'interfaccia a `ReactTransitions`. Questo è un semplice elemento che racchiude tutti i componenti che desideri animare. Ecco un esempio in cui facciamo apparire e scomparire gli elementi di una lista. - -```javascript{28-30} -var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup; - -var TodoList = React.createClass({ - getInitialState: function() { - return {items: ['ciao', 'mondo', 'clicca', 'qui']}; - }, - handleAdd: function() { - var newItems = - this.state.items.concat([prompt('Scrivi del testo')]); - this.setState({items: newItems}); - }, - handleRemove: function(i) { - var newItems = this.state.items; - newItems.splice(i, 1); - this.setState({items: newItems}); - }, - render: function() { - var items = this.state.items.map(function(item, i) { - return ( -
    - {item} -
    - ); - }.bind(this)); - return ( -
    - - - {items} - -
    - ); - } -}); -``` -> Nota: -> -> Devi fornire [l'attributo `key`](/react/docs/multiple-components.html#dynamic-children) per tutti i figli di `ReactCSSTransitionGroup`, anche quando stai visualizzando un singolo elemento. Questo è il modo in cui React determina quali figli sono stati aggiunti, rimossi, o sono rimasti. - -In questo componente, quando un nuovo elemento viene aggiunto a `ReactCSSTransitionGroup` riceverà la classe CSS `example-enter` e la classe CSS `example-enter-active` allo scatto successivo. Questa è una convenzione basata sul valore della proprietà `transitionName`. - -Puoi usare queste classi per scatenare una animazione o transizione CSS. Ad esempio, prova ad aggiungere questo CSS e aggiungere un nuovo elemento alla lista: - -```css -.example-enter { - opacity: 0.01; -} - -.example-enter.example-enter-active { - opacity: 1; - transition: opacity 500ms ease-in; -} - -.example-leave { - opacity: 1; -} - -.example-leave.example-leave-active { - opacity: 0.01; - transition: opacity 300ms ease-in; -} -``` - -Ti accorgerai che la durata delle animazioni devono essere specificate sia nel CSS che nel metodo render; questo suggerisce a React quando rimuovere le classi di animazione dall'elemento e -- se sta venendo rimosso -- quando rimuovere l'elemento dal DOM. - -### Animare il Montaggio Iniziale - -`ReactCSSTransitionGroup` fornisce la proprietà opzionale `transitionAppear`, per aggiungere una fase aggiuntiva di transizione al montaggio iniziale del componente. In genere non c'è alcuna fase di transizione al montaggio iniziale in quanto il valore predefinito di `transitionAppear` è `false`. L'esempio seguente passa la proprietà `transitionAppear` con il valore `true`. - -```javascript{3-5} - render: function() { - return ( - -

    Dissolvenza al Montaggio Iniziale

    -
    - ); - } -``` - -Durante il montaggio iniziale `ReactCSSTransitionGroup` otterrà la classe CSS `example-appear` e la classe CSS `example-appear-active` allo scatto successivo. - -```css -.example-appear { - opacity: 0.01; -} - -.example-appear.example-appear-active { - opacity: 1; - transition: opacity .5s ease-in; -} -``` - -Al montaggio iniziale, tutti i figli di `ReactCSSTransitionGroup` saranno marcati come `appear` ma non `enter`. Tuttavia, tutti i figli aggiunti in seguito ad un `ReactCSSTransitionGroup` esistente saranno marcati come `enter` ma non `appear`. - -> Nota: -> -> La proprietà `transitionAppear` è stata aggiunta a `ReactCSSTransitionGroup` nella versione `0.13`. Per mantenere la compatibilità con le versioni precedenti, il valore predefinito è impostato a `false`. - -### Classi Personalizzate - -È anche possibile usare nomi di classi personalizzate per ciascuna delle fasi delle tue transizioni. Anziché passare una stringa come valore di `transitionName` puoi assegnare un oggetto che contiene i nomi delle classi `enter` o `leave`, oppure un oggetto contenente i nomi delle classi per `enter`, `enter-active`, `leave-active`e `leave`. Se vengono forniti soltanto i nomi delle classi enter e leave, le classi per enter-active e leave-active saranno determinate aggiungendo il suffisso '-active' ai rispettivi nomi delle classi. Ecco due esempi che usano le classi personalizzate: - -```javascript - ... - - {item} - - - - {item2} - - ... -``` - -### I Gruppi di Animazioni Devono Essere Montati per Funzionare - -Per applicare le transizioni ai suoi figli, il `ReactCSSTransitionGroup` deve già essere montato nel DOM oppure la proprietà `transitionAppear` deve essere impostata a `true`. L'esempio seguente non funziona, poiché `ReactCSSTransitionGroup` sta venendo montato assieme al nuovo elemento, anziché il nuovo elemento venire montato dentro di esso. Confronta questo esempio con la sezione precedente [Per Cominciare](#getting-started) per notare la differenza. - -```javascript{12-15} - render: function() { - var items = this.state.items.map(function(item, i) { - return ( -
    - - {item} - -
    - ); - }, this); - return ( -
    - - {items} -
    - ); - } -``` - -### Animare Uno o Nessun Elemento - -Nell'esempio precedente, abbiamo visualizzato una lista di elementi in `ReactCSSTransitionGroup`. Tuttavia, i figli di `ReactCSSTransitionGroup` possono anche essere un solo o nessun elemento. Questo rende possibile animare un singolo elemento che viene aggiunto o rimosso. Similarmente, puoi animare un nuovo elemento che sistituisce l'elemento corrente. Ad esempio, possiamo implementare un semplice carosello di immagini come segue: - -```javascript{10-12} -var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup; - -var ImageCarousel = React.createClass({ - propTypes: { - imageSrc: React.PropTypes.string.isRequired - }, - render: function() { - return ( -
    - - - -
    - ); - } -}); -``` - -### Disattivare le Animazioni - -Se lo desideri, puoi disattivare le animazioni `enter` o `leave`. Ad esempio, a volte potresti volere un'animazione per `enter` ma non una per `leave`, ma `ReactCSSTransitionGroup` attende che l'animazione sia completata prima di rimuovere il tuo nodo DOM. Puoi aggiungere le proprietà `transitionEnter={false}` o `transitionLeave={false}` a `ReactCSSTransitionGroup` per disattivare le rispettive animazioni. - -> Nota: -> -> Quando si usa `ReactCSSTransitionGroup`, non c'è alcun modo per cui i tuoi componenti vengano avvisati quando la transizione è terminata o per effettuare una logica complessa durante l'animazione. Se vuoi un controllo più fine, puoi usare la API di basso livello `ReactTransitionGroup` che fornisce degli hook che puoi utilizzare per effettuare transizioni personalizzate. - -## API di Basso Livello: `ReactTransitionGroup` - -`ReactTransitionGroup` è la base per le animazioni. È accessibile come `React.addons.TransitionGroup`. Quando vi sono aggiunti o rimossi dichiarativamente dei figli (come negli esempi precedenti) degli speciali hook del ciclo di vita sono invocati su di essi. - -### `componentWillAppear(callback)` - -Viene chiamato allo stesso momento di `componentDidMount()` per i componenti inizialmente montati in un `TransitionGroup`. Bloccherà l'esecuzione di altre animazioni finché `callback` non viene chiamata. Viene chiamata solo durante il rendering iniziale di un `TransitionGroup`. - -### `componentDidAppear()` - -Viene chiamato dopo che la funzione `callback` passata a `componentWillAppear` è stata chiamata. - -### `componentWillEnter(callback)` - -Viene chiamato allo stesso momento di `componentDidMount()` per i componenti aggiunti ad un `TransitionGroup` esistente. Bloccherà l'esecuzione di altre animazioni finché `callback` non viene chiamata. Non viene chiamata durante il rendering iniziale di un `TransitionGroup`. - -### `componentDidEnter()` - -Viene chiamato dopo che la funzione `callback` passata a `componentWillEnter` è stata chiamata. - -### `componentWillLeave(callback)` - -Viene chiamato quando il figlio è stato rimosso dal `ReactTransitionGroup`. Nonostante il figlio sia stato rimosso, `ReactTransitionGroup` lo manterrà nel DOM finché `callback` non viene chiamata. - -### `componentDidLeave()` - -Viene chiamato quando la `callback` `willLeave` viene chiamata (contemporaneamente a `componentWillUnmount`). - -### Rendering di un Componente Diverso - -In maniera predefinita, `ReactTransitionGroup` viene visualizzato come uno `span`. Puoi cambiare questo comportamento fornento una proprietà `component`. Ad esempio, ecco come puoi visualizzare un `
      `: - -```javascript{1} - - ... - -``` - -È possibile utilizzare ciascun componente DOM che React può visualizzare. Tuttavia, `component` non deve necessariamente essere un componente DOM. Può infatti essere qualunque componente React; anche componenti scritti da te! - -> Nota: -> -> Prima della v0.12, quando venivano usati componenti DOM, la proprietà `component` doveva essere un riferimento a `React.DOM.*`. Dal momento che il componente è semplicemente passato a `React.createElement`, deve ora essere una stringa. Per componenti compositi si deve passare il metodo factory. - -Ciascuna proprietà aggiuntiva definita dall'utente diverrà una proprietà del componente visualizzato. Ad esempio, ecco come visualizzeresti un `
        ` con una classe CSS: - -```javascript{1} - - ... - -``` diff --git a/docs/docs/10.1-animation.ja-JP.md b/docs/docs/10.1-animation.ja-JP.md deleted file mode 100644 index ac381de3f8..0000000000 --- a/docs/docs/10.1-animation.ja-JP.md +++ /dev/null @@ -1,230 +0,0 @@ ---- -id: animation -title: アニメーション -permalink: docs/animation-ja-JP.html -prev: addons-ja-JP.html -next: two-way-binding-helpers-ja-JP.html ---- - -ReactはアニメーションのためにローレベルAPIとして `ReactTransitionGroup` アドオンコンポーネントと、基本的なCSSアニメーションとトランジションを簡単に実行するために `ReactCSSTransitionGroup` を提供しています。 - -## ハイレベルAPI: `ReactCSSTransitionGroup` - -`ReactCSSTransitionGroup` は `ReactTransitionGroup` に基づいており、ReactコンポーネントがDOMを作成したり、削除したりする際に、CSSのトランジションとアニメーションを行う簡単な方法です。これは、素晴らしい[ng-animate](http://www.nganimate.org/)ライブラリにインスパイアされています。 - -### はじめに - -`ReactCSSTransitionGroup` は `ReactTransitions` のインターフェースです。アニメーションに関心がある全てのコンポーネントをラップする単純な要素です。以下が、リストのアイテムをフェードインやフェードアウトさせる例です。 - -```javascript{28-30} -var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup; - -var TodoList = React.createClass({ - getInitialState: function() { - return {items: ['hello', 'world', 'click', 'me']}; - }, - handleAdd: function() { - var newItems = - this.state.items.concat([prompt('Enter some text')]); - this.setState({items: newItems}); - }, - handleRemove: function(i) { - var newItems = this.state.items; - newItems.splice(i, 1); - this.setState({items: newItems}); - }, - render: function() { - var items = this.state.items.map(function(item, i) { - return ( -
        - {item} -
        - ); - }.bind(this)); - return ( -
        - - - {items} - -
        - ); - } -}); -``` -> 注意: -> もし子要素を1つだけレンダリングするとしても、 `ReactCSSTransitionGroup` の全ての子要素に提供しなければなりません。これが、Reactが、子要素が作成されているか、削除されたか、あるいはそのままであるか判断する方法です。 - -このコンポーネントでは、 `ReactCSSTransitionGroup` に新しいアイテムが追加された次の瞬間に、 `example-enter` CSSクラスと `example-enter-active` CSSクラスを得ます。これは、 `transitionName` propに基づく習慣です。 - -これらのクラスはCSSアニメーションやトランジションのトリガーとして使うことができます。例えば、以下のようにして、このCSSを加え、新しいリストアイテムを加えてみましょう。 - -```css -.example-enter { - opacity: 0.01; - transition: opacity .5s ease-in; -} - -.example-enter.example-enter-active { - opacity: 1; -} -``` - -アイテムを削除しようとしたときに、 `ReactCSSTransitionGroup` がDOMの中にそれを保持していることに気づくでしょう。縮小化されていないReactのビルドとアドオンを使っているならば、Reactがアニメーションやトランジションが起こることを予期しているという警告が出るでしょう。これは、 `ReactCSSTransitionGroup` がアニメーションが終わるまでDOM要素をページに保持し続けるからです。以下のCSSを加えてみましょう。 - -```css -.example-leave { - opacity: 1; - transition: opacity .5s ease-in; -} - -.example-leave.example-leave-active { - opacity: 0.01; -} -``` - -### 最初のマウントにおけるアニメーション - -`ReactCSSTransitionGroup` は `transitionAppear` というオプションのプロパティを提供します。コンポーネントの最初のマウントの際に、更なるトランジションのフェーズを加えるためです。一般的には、 `transitionAppear` が `false` である最初のマウントの際にはトランジションのフェーズはありません。 `transitionAppear` プロパティを値が `true` である状態で渡す以下の例を見てみましょう。 - -```javascript{3-5} - render: function() { - return ( - -

        Fading at Initial Mount

        -
        - ); - } -``` - -最初のマウントの間、 `ReactCSSTransitionGroup` は `example-appear` CSSクラスを得て、次の瞬間に `example-appear-active` CSSクラスを加えます。 - -```css -.example-appear { - opacity: 0.01; - transition: opacity .5s ease-in; -} - -.example-appear.example-appear-active { - opacity: 1; -} -``` - -最初のマウントの際には、 `ReactCSSTransitionGroup` の全ての子要素は `appear` しますが、 `enter` はしません。一方、存在する `ReactCSSTransitionGroup` に後から加えられた子要素は全て `enter` しますが、 `appear` はしません。 - -> 注意: -> `transitionAppear` プロパティはバージョン `0.13` で `ReactCSSTransitionGroup` に加えられました。後方互換性を維持するために、デフォルトの値は `false` に指定されています。 - -### アニメーショングループを動かすためには、マウントされている必要があります - -子要素にトランジションを適用するためには、 `ReactCSSTransitionGroup` はすでにDOMにマウントされているか、 `transitionAppear` プロパティに `true` がセットされている必要があります。以下の例は動きません。 `ReactCSSTransitionGroup` が新しいアイテムとともにマウントされており、新しいマウントがマウントされていないからです。これと上の[はじめに](#はじめに) とで違いを比較してみてください。 - -```javascript{12-15} - render: function() { - var items = this.state.items.map(function(item, i) { - return ( -
        - - {item} - -
        - ); - }, this); - return ( -
        - - {items} -
        - ); - } -``` - -### 1個か0個のアイテムをアニメーションする - -上の例では、 `ReactCSSTransitionGroup` にアイテムのリストをレンダリングしました。しかし、 `ReactCSSTransitionGroup` の子要素は1個や0個のアイテムになり得ます。単一の要素が作成や削除のアニメーションを可能にします。同様に、現在の要素を置き換える新しい要素をアニメーションできます。例えば、以下のように、1つの画像でカルーセルを実行できます。 - -```javascript{10-12} -var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup; - -var ImageCarousel = React.createClass({ - propTypes: { - imageSrc: React.PropTypes.string.isRequired - }, - render: function() { - return ( -
        - - - -
        - ); - } -}); -``` - -### アニメーションを作動させないようにする - -もししたいならば、 `enter` や `leave` のアニメーションを無効にすることもできます。例えば、 `enter` アニメーションは行いたいが、 `leave` のアニメーションは行いたくない場合があるでしょう。しかし、 `ReactCSSTransitionGroup` はDOMのノードが削除される前にアニメーションが終わるのを待ちます。`ReactCSSTransitionGroup` がそれらのアニメーションを無効化するために、 `transitionEnter={false}` や `transitionLeave={false}` といったプロパティを追加することができます。 - -> 注意: -> `ReactCSSTransitionGroup` を使う際には、コンポーネントがトランジションが終わったことを検知したり、アニメーション関連でさらに複雑なロジックを実行するといったことはできません。更に細かな制御を求める場合は、トランジションをカスタムするために必要なフックを提供するローレベルの `ReactTransitionGroup` APIを使用できます。 - -## ローレベルAPI: `ReactTransitionGroup` - -`ReactTransitionGroup` はアニメーションの基盤です。 `React.addons.TransitionGroup` と同じくらい簡単に使用できます。これによって(上記の例のように)、宣言的に子要素が追加されたり削除されたりするときに、それらの上で特別なライフサイクルのフックが呼ばれます。 - -### `componentWillAppear(callback)` - -このメソッドは `TransitionGroup` の中で最初にマウントされるコンポーネントのために `componentDidMount()` と同時に呼ばれます。これは、 `callback` が呼ばれるまで、他のアニメーションが発生するのをブロックします。これは、 `TransitionGroup` の最初のレンダリングのときにのみ呼ばれます。 - -### `componentDidAppear()` - - `componentWillAppear` が呼ばれて渡される `callback` 関数の後に呼ばれます。 - -### `componentWillEnter(callback)` - -これは、存在する `TransitionGroup` に追加されるコンポーネントのために、 `componentDidMount()` と同時に呼ばれます。これは、 `callback` が呼ばれるまで、他のアニメーションが発生するのをブロックします。これは、 `TransitionGroup` の最初のレンダリングのときには呼ばれません。 - -### `componentDidEnter()` - -`componentWillEnter` が呼ばれて渡される `callback` 関数の後に呼ばれます。 - -### `componentWillLeave(callback)` - -これは、 `ReactTransitionGroup` から子要素が削除されたときに呼ばれます。子要素が削除されても、 `ReactTransitionGroup` は `callback` が呼ばれるまでDOMの中に子要素を保持し続けます。 - -### `componentDidLeave()` - -これは、 `willLeave` の `callback` が呼ばれた際に呼ばれます( `componentWillUnmount` と同時です)。 - -### 異なるコンポーネントをレンダリングする - -デフォルトで、 `ReactTransitionGroup` は `span` としてレンダリングされます。この動きは、 `component` プロパティによって変更できます。例えば、 `
          ` をレンダリングしたい場合は以下のようになります。 - -```javascript{1} - - ... - -``` - -Reactがレンダリングできる全てのDOMコンポーネントが使用できます。しかし、 `component` はDOMコンポーネントである必要はありません。あなたが求めているどんなReactのコンポーネントにもなり得ます。あなた自身が記述したものにもです! - -> 注意: -> v0.12以前では、DOMのコンポーネントを使用する際には、 `component` プロパティが `React.DOM.*` を参照している必要がありました。コンポーネントが単純に `React.createElement`から渡されていたからです。これは今は文字列である必要があります。複合的なコンポーネントは複合的なものを渡す必要があります。 - -全ての付加的な、ユーザー定義のプロパティはレンダリングされたコンポーネントのプロパティになります。例えば、以下はCSSクラスとともに `
            ` をレンダリングする方法です。 - -```javascript{1} - - ... - -``` diff --git a/docs/docs/10.1-animation.ko-KR.md b/docs/docs/10.1-animation.ko-KR.md deleted file mode 100644 index 7bc766c6ab..0000000000 --- a/docs/docs/10.1-animation.ko-KR.md +++ /dev/null @@ -1,258 +0,0 @@ ---- -id: animation-ko-KR -title: 애니메이션 -permalink: docs/animation-ko-KR.html -prev: addons-ko-KR.html -next: two-way-binding-helpers-ko-KR.html ---- - -React에는 애니메이션을 위한 저 수준 API로 `ReactTransitionGroup` 애드온 컴포넌트가 있고 간단히 기초 CSS 애니메이션과 트랜지션을 구현할 수 있는 `ReactCSSTransitionGroup`가 있습니다. - -## 고 레벨 API: `ReactCSSTransitionGroup` - -`ReactCSSTransitionGroup`는 `ReactTransitionGroup`를 기반으로 React 컴포넌트가 DOM에 들어가거나 나올때의 CSS의 트랜지션과 애니메이션을 구현하기 쉽게합니다. 이는 [ng-animate](http://www.nganimate.org/) 라이브러리에 영향을 받았습니다. - -### 시작하기 - -`ReactCSSTransitionGroup`은 `ReactTransitions`을 위한 인터페이스입니다. 이는 애니메이션을 제어할 모든 컴포넌트를 감싸는 하나의 엘리먼트 입니다. 아래는 목록의 아이템을 페이드 인/아웃하는 간단한 예제입니다. - -```javascript{28-30} -var ReactCSSTransitionGroup = require('react-addons-css-transition-group'); - -var TodoList = React.createClass({ - getInitialState: function() { - return {items: ['hello', 'world', 'click', 'me']}; - }, - handleAdd: function() { - var newItems = - this.state.items.concat([prompt('Enter some text')]); - this.setState({items: newItems}); - }, - handleRemove: function(i) { - var newItems = this.state.items; - newItems.splice(i, 1); - this.setState({items: newItems}); - }, - render: function() { - var items = this.state.items.map(function(item, i) { - return ( -
            - {item} -
            - ); - }.bind(this)); - return ( -
            - - - {items} - -
            - ); - } -}); -``` - -> 주의: -> -> `ReactCSSTransitionGroup`의 모든 자식은 [`key` 어트리뷰트](/react/docs/multiple-components-ko-KR.html#동적-자식)를 반드시 만들어야 합니다. 한 아이템을 렌더할 때도 예외는 아닙니다. 키는 React가 어떤 자식이 들어오고, 나가고, 머무르는지 파악할 때 사용합니다. - -이 컴포넌트에서 새로운 아이템이 `ReactCSSTransitionGroup`에 추가되면 `example-enter` 아이템은 CSS 클래스를 가지게 되고 다음 순간에 `example-enter-active` CSS 클래스가 추가됩니다. 이는 `transitionName` prop을 기반으로 한 관례입니다. - -이 클래스들은 CSS 애니메이션이나 트랜지션을 일으키는데 사용할 수 있습니다. 예를 들어, 이 CSS를 넣은 후 아이템을 추가해 보세요. - -```css -.example-enter { - opacity: 0.01; -} - -.example-enter.example-enter-active { - opacity: 1; - transition: opacity 500ms ease-in; -} - -.example-leave { - opacity: 1; -} - -.example-leave.example-leave-active { - opacity: 0.01; - transition: opacity 300ms ease-in; -} -``` - -에니메이션 기간이 CSS와 렌더 메소드 양쪽에 지정될 필요가 있다는 것에 주의하셔야 합니다. 이는 엘리먼트에서 애니메이션 클래스를 제거할 때 (만약 남아있다면) DOM에서 엘리먼트를 제거할 때 React에 알려줍니다. - -### 처음 마운트에서 애니메이션 하기 - -`ReactCSSTransitionGroup`은 컴포넌트를 처음 마운트할 때 추가 트렌지션 단계를 추가하기 위해, 선택적인 prop `transitionAppear`를 제공합니다. 일반적으로 처음 마운트할 때 트렌지션 단계를 넣지 않기 때문에 `transitionAppear`의 기본 값은 `false`입니다. 뒤의 예제는 `transitionAppear` prop에 `true` 값을 넘기고 있습니다. - -```javascript{3-5} - render: function() { - return ( - -

            Fading at Initial Mount

            -
            - ); - } -``` - -처음 마운트할 때 `ReactCSSTransitionGroup`은 `example-appear` CSS 클래스를 받고 그 다음에 `example-appear-active` CSS 클래스가 추가됩니다. - -```css -.example-appear { - opacity: 0.01; -} - -.example-appear.example-appear-active { - opacity: 1; - transition: opacity .5s ease-in; -} -``` - -처음 마운트할 때, `ReactCSSTransitionGroup`의 모든 자식은 `appear`하지만 `enter`하지 않습니다. 하지만, 존재하는 `ReactCSSTransitionGroup`에 추가되는 모든 자식은 `enter`하지만 `appear`하지 않습니다. - -> 주의: -> -> `transitionAppear` prop은 버전 `0.13`에서 `ReactCSSTransitionGroup`에 추가되었습니다. 하위 호환성을 생각해서, 기본 값은 `false`로 설정되어 있습니다. - -### 커스텀 클래스 - -트렌지션의 각 단계에서 커스텀 클래스 이름을 사용할 수도 있습니다. transitionName에 문자열을 넘기는 대신 `enter`, `leave` 같은 클래스 이름의 객체나 `enter`, `enter-active`, `leave-active`, `leave`같은 클래스 이름의 객체를 넘길 수 있습니다. enter, leave 클래스만 있다면, enter-active, leave-active 클래스는 클래스 이름 뒤에 '-active'를 붙여서 정할 수 있습니다. 커스텀 클래스를 사용한 예제입니다. - -```javascript - ... - - {item} - - - - {item2} - - ... -``` - -### 애니메이션 그룹이 작동하려면 마운트가 필요 - -자식들에게 트랜지션을 적용하려면 `ReactCSSTransitionGroup`은 이미 DOM에 마운트되어 있거나 prop `transitionAppear`가 `true`로 설정되어야만 합니다. 예를 들어, 밑의 코드는 동작하지 않을 것입니다. 왜냐하면 `ReactCSSTransitionGroup` 안에서 새 아이템을 마운트하는 대신 새 아이템과 같이 `ReactCSSTransitionGroup`를 마운트했기 때문입니다. 이 것을 위에 있는 [시작하기](#시작하기) 항목과 비교해보세요. - -```javascript{12-15} - render: function() { - var items = this.state.items.map(function(item, i) { - return ( -
            - - {item} - -
            - ); - }, this); - return ( -
            - - {items} -
            - ); - } -``` - -### 아이템 하나이거나 없을 때의 애니메이션 - -위의 예제에서 `ReactCSSTransitionGroup`에 아이템 목록을 렌더했지만, `ReactCSSTransitionGroup`의 자식은 하나이거나 없을 수도 있습니다. 이는 한 엘리먼트가 들어오고 나가는 것의 애니메이션을 가능하게 합니다. 비슷하게, 현재 엘리먼트가 나가는 동안 새 앨리먼트의 애니메이션을 하면, 새 엘리먼트가 현재 엘리먼트를 교체하는 애니메이션을 만들 수 있습니다. 예를 들어 이렇게 간단한 이미지 회전 베너(carousel)를 구현할 수 있습니다. - -```javascript{10-12} -var ReactCSSTransitionGroup = require('react-addons-css-transition-group'); - -var ImageCarousel = React.createClass({ - propTypes: { - imageSrc: React.PropTypes.string.isRequired - }, - render: function() { - return ( -
            - - - -
            - ); - } -}); -``` - -### 애니메이션 비활성화 - -원한다면 `enter`나 `leave` 애니메이션을 비활성화 할 수 있습니다. 예를 들어, `enter` 애니메이션만 필요하고 `leave` 애니메이션은 필요없지만, `ReactCSSTransitionGroup`이 DOM 노드를 없애기 전 애니메이션이 완료되길 기다리고 있는 경우에 사용할 수 있습니다. `ReactCSSTransitionGroup`에 `transitionEnter={false}`나 `transitionLeave={false}` props를 추가하면 그 애니메이션을 비활성화 할 수 있습니다. - -> 주의: -> -> `ReactCSSTransitionGroup`를 사용할 때는, 트랜지션이 종료되었을 때나 애니메이션 근처에서 더 복잡한 로직을 실행할 때 컴포넌트에 통지할 방법이 없습니다. 보다 세밀하게 제어하고 싶다면, 커스텀 트랜지션에 필요한 훅을 제공하는 저수준 `ReactTransitionGroup` API를 이용할 수 있습니다. - -## 저수준 API: `ReactTransitionGroup` - -`ReactTransitionGroup`은 애니메이션의 기초입니다. 이는 `require('react-addons-transition-group')`으로 접근할 수 있습니다. 위의 예제처럼 자식들이 선언적으로 여기에 추가되거나 삭제되는 경우, 특별한 훅이 이 생명주기에서 호출됩니다. - -### `componentWillAppear(callback)` - -이미 있는 `TransitionGroup`에 컴포넌트를 추가할 때 호출되는 `componentDidMount()`와 같이 호출됩니다. 이는 `callback`이 호출될 때까지 다른 애니메이션을 막습니다. `TransitionGroup`의 최초 렌더에서만 호출됩니다. - -### `componentDidAppear()` - -이는 `componentWillAppear`에 넘겨졌던 `callback` 함수가 호출된 다음에 호출됩니다. - -### `componentWillEnter(callback)` - -이미 있는 `TransitionGroup`에 컴포넌트를 추가할 때 호출되는 `componentDidMount()`와 같이 호출됩니다. 이는 `callback`이 호출될 때까지 다른 애니메이션을 막습니다. `TransitionGroup`의 최조 렌더에서는 불려지지 않습니다. - -### `componentDidEnter()` - -이는 `componentWillEnter`에 넘겨주었던 `callback` 함수가 호출된 다음에 호출됩니다. - -### `componentWillLeave(callback)` - -이는 `ReactTransitionGroup`에서 자식이 제거되었을 때 호출됩니다. 자식이 제거되었다고 해도 `ReactTransitionGroup`는 `callback`이 호출될 때까지 DOM에 자식을 남겨둡니다. - -### `componentDidLeave()` - -이는 `willLeave` `callback`이 호출될 때 호출됩니다. (`componentWillUnmount`와 같은 타이밍) - -### 다른 컴포넌트 렌더하기 - -기본적으로 `ReactTransitionGroup`은 `span`으로 렌더합니다. `component` prop으로 이 행동을 바꿀 수 있습니다. 예를 들어, `
              `을 렌더하고 싶다면 이렇게 하면 됩니다. - -```javascript{1} - - ... - -``` - -React가 렌더할 수 있는 DOM 컴포넌트는 전부 사용할 수 있습니다. 하지만 `component`가 DOM 컴포넌트일 필요는 없습니다. React 컴포넌트라면 무엇이든 넣을 수 있습니다. 직접 구현한 컴포넌트여도 됩니다! 그냥 `component={List}`를 적으면 컴포넌트는 `this.props.children`로 받을 수 있습니다. - -사용자 정의를 포함한 어떤 프로퍼티도 렌더된 컴포넌트의 프로퍼티가 됩니다. 예를 들어, `
                `에 CSS 클래스를 넣어서 렌더하려면 이렇게 하면 됩니다. - -```javascript{1} - - ... - -``` diff --git a/docs/docs/10.1-animation.zh-CN.md b/docs/docs/10.1-animation.zh-CN.md deleted file mode 100644 index b374a005c4..0000000000 --- a/docs/docs/10.1-animation.zh-CN.md +++ /dev/null @@ -1,258 +0,0 @@ ---- -id: animation-zh-CN -title: 动画 -permalink: docs/animation-zh-CN.html -prev: addons-zh-CN.html -next: two-way-binding-helpers-zh-CN.html ---- - -React 提供了一个 `ReactTransitionGroup` 插件作为动画的底层API,和一个 `ReactCSSTransitionGroup` 用于轻松实现基础的CSS动画和过渡。 - -## 高级 API: `ReactCSSTransitionGroup` - -`ReactCSSTransitionGroup` 基于 `ReactTransitionGroup` 是一个当React组件进入或离开DOM时,执行CSS动画和过渡的简单方法。它的灵感来自于杰出的 [ng-animate](http://www.nganimate.org/) 库。 - -### 入门指南 - -`ReactCSSTransitionGroup` 是 `ReactTransitions` 的接口。这是一个简单的元素,包裹了所有你感兴趣的动画组件。这里是一个淡入和淡出列表项目的例子。 - -```javascript{28-30} -var ReactCSSTransitionGroup = require('react-addons-css-transition-group'); - -var TodoList = React.createClass({ - getInitialState: function() { - return {items: ['hello', 'world', 'click', 'me']}; - }, - handleAdd: function() { - var newItems = - this.state.items.concat([prompt('Enter some text')]); - this.setState({items: newItems}); - }, - handleRemove: function(i) { - var newItems = this.state.items.slice(); - newItems.splice(i, 1); - this.setState({items: newItems}); - }, - render: function() { - var items = this.state.items.map(function(item, i) { - return ( -
                - {item} -
                - ); - }.bind(this)); - return ( -
                - - - {items} - -
                - ); - } -}); -``` -> 注意: -> -> 你必须为`ReactCSSTransitionGroup`的所有子级提供 [ `key` 属性](/react/docs/multiple-components.html#dynamic-children),即使只渲染一个项目。这就是React将决定哪一个子级进入,离开,或者停留 - -在这个组件,当一个新的项目被添加到 `ReactCSSTransitionGroup` ,他将得到`example-enter` CSS类 并且在下一刻`example-enter-active` CSS类被添加。这是一个基于`transitionName` prop 的约定。 - -你可以使用这些类来触发CSS动画和过渡。比如,尝试添加这个CSS和添加一个新的列表项: - -```css -.example-enter { - opacity: 0.01; -} - -.example-enter.example-enter-active { - opacity: 1; - transition: opacity 500ms ease-in; -} - -.example-leave { - opacity: 1; -} - -.example-leave.example-leave-active { - opacity: 0.01; - transition: opacity 300ms ease-in; -} -``` - -你会注意到动画持续时间需要被同时在CSS和渲染方法里被指定;这告诉React什么时候从元素中移除动画类,并且 -- 如果它正在离开 -- 何时从DOM移除元素。 - -### 让初始化挂载动画 - -`ReactCSSTransitionGroup` 提供了可选的prop `transitionAppear`,来为在组件初始挂载添加一个额外的过渡阶段。 通常在初始化挂载时没有过渡阶段因为`transitionAppear` 的默认值为`false`。下面是一个传递`transitionAppear` 为值`true`的例子。 - -```javascript{3-5} - render: function() { - return ( - -

                Fading at Initial Mount

                -
                - ); - } -``` - -在初始化挂载时 `ReactCSSTransitionGroup` 将获得`example-appear` CSS类 并且`example-appear-active` CSS 类在下一刻被添加。 - -```css -.example-appear { - opacity: 0.01; -} - -.example-appear.example-appear-active { - opacity: 1; - transition: opacity .5s ease-in; -} -``` - -在初始化挂载,所有的 `ReactCSSTransitionGroup` 子级将会 `appear` 但不 `enter`。然而,所有后来添加到已存在的 `ReactCSSTransitionGroup` 的子级将 `enter` 但不 `appear`。 - -> 注意: -> -> prop `transitionAppear` 在版本 `0.13` 被添加到 `ReactCSSTransitionGroup`。为了保持向后兼容,默认值被设置为 `false`。 - -### 制定类 - -可以为你的每一步过渡使用制定类名字。代理传递一个字符串到transitionName,你可以传递一个含有`enter` 或者`leave` 类名的对象,或者一个含有 `enter`, `enter-active`, `leave-active`, 和 `leave` 类名的对象。只要提供了enter 和 leave 的类,enter-active 和 leave-active 类会被决定为后缀'-active' 到类名的尾部。这里是两个使用制定类的例子: - -```javascript - ... - - {item} - - - - {item2} - - ... -``` - -### 动画组必须挂载才工作 - -为了使过渡效果应用到子级上,`ReactCSSTransitionGroup`必须已经挂载到了DOM或者 prop `transitionAppear` 必须被设置为 `true`。下面的例子不会工作,因为 `ReactCSSTransitionGroup` 随同新项目被挂载,而不是新项目在它内部被挂载。将这与上面的[入门指南](#入门指南)部分比较一下,看看不同。 - -```javascript{12-15} - render: function() { - var items = this.state.items.map(function(item, i) { - return ( -
                - - {item} - -
                - ); - }, this); - return ( -
                - - {items} -
                - ); - } -``` - -### 动画一个或者零个项目 Animating One or Zero Items - -在上面的例子中,我们渲染了一系列的项目到`ReactCSSTransitionGroup`里。然而 `ReactCSSTransitionGroup` 的子级同样可以是一个或零个项目。这使它能够动画化单个元素的进入和离开。同样,你可以动画化一个新的元素替换当前元素。例如,我们可以像这样实现一个简单的图片轮播器: - -```javascript{10-12} -var ReactCSSTransitionGroup = require('react-addons-css-transition-group'); - -var ImageCarousel = React.createClass({ - propTypes: { - imageSrc: React.PropTypes.string.isRequired - }, - render: function() { - return ( -
                - - - -
                - ); - } -}); -``` - -### 禁用动画 - -如果你想,你可以禁用 `enter` 或者 `leave` 动画。例如,有时你可能想要一个 `enter` 动画,不要 `leave` 动画,但是 `ReactCSSTransitionGroup` 会在移除你的DOM节点之前等待一个动画完成。你可以添加`transitionEnter={false}` 或者 `transitionLeave={false}` props 到 `ReactCSSTransitionGroup` 来禁用这些动画。 - -> 注意: -> -> 当使用 `ReactCSSTransitionGroup` 时,没有办法通知你的组件何时过渡效果结束或者在动画时执行任何复杂的逻辑运算。如果你想要更多细粒度的控制,你可以使用底层的 `ReactTransitionGroup` API,它提供了你自定义过渡效果所需要的挂钩。 - -## 底层 API: `ReactTransitionGroup` - -`ReactTransitionGroup`是动画的基础。它通过 `require('react-addons-transition-group')` 访问。当子级被声明式的从其中添加或移除(就像上面的例子)时,特殊的生命周期挂钩会在它们上面被调用。 - -### `componentWillAppear(callback)` - -对于被初始化挂载到 `TransitionGroup` 的组件,它和 `componentDidMount()` 在相同时间被调用 。它将会阻塞其它动画发生,直到`callback`被调用。它只会在 `TransitionGroup` 初始化渲染时被调用。 - -### `componentDidAppear()` - -在 传给`componentWillAppear` 的 `回调` 函数被调用后调用。 - -### `componentWillEnter(callback)` - -对于被添加到已存在的 `TransitionGroup` 的组件,它和 `componentDidMount()` 在相同时间被调用 。它将会阻塞其它动画发生,直到`callback`被调用。它不会在 `TransitionGroup` 初始化渲染时被调用。 - -### `componentDidEnter()` - -在传给 `componentWillEnter` 的`回调`函数被调用之后调用。 - -### `componentWillLeave(callback)` - -在子级从 `ReactTransitionGroup` 中移除时调用。虽然子级被移除了,`ReactTransitionGroup` 将会保持它在DOM中,直到`callback`被调用。 - -### `componentDidLeave()` - -在`willLeave` `callback` 被调用的时候调用(与 `componentWillUnmount` 同一时间)。 - -### 渲染一个不同的组件 - -默认情况下 `ReactTransitionGroup` 渲染为一个 `span`。你可以通过提供一个 `component` prop 来改变这种行为。例如,下面是你将如何渲染一个`
                  `: - -```javascript{1} - - ... - -``` - -每一个React能渲染的DOM组件都是可用的。然而,`组件`不需要是一个DOM组件。它可以是任何你想要的React组件;甚至是你自己已经写好的!只要写 `component={List}` 你的组件会收到 `this.props.children` - - -任何额外的、用户定义的属性将会成为已渲染的组件的属性。例如,以下是你将如何渲染一个带有css类的 `
                    `: - -```javascript{1} - - ... - -``` diff --git a/docs/docs/10.10-shallow-compare.zh-CN.md b/docs/docs/10.10-shallow-compare.zh-CN.md deleted file mode 100644 index 9bb61cb98f..0000000000 --- a/docs/docs/10.10-shallow-compare.zh-CN.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -id: shallow-compare-zh-CN -title: 浅比较 -permalink: docs/shallow-compare-zh-CN.html -prev: perf-zh-CN.html -next: advanced-performance-zh-CN.html ---- - -`shallowCompare` 是一个辅助函数 在以ES6类使用React时,完成和 `PureRenderMixin` 相同的功能。 - -如果你的React组件的绘制函数是 “干净的” (换句话说,它在给定的 props 和 state 下绘制相同的结果),你可以使用这个辅助函数以在某些情况下提升性能。 - -例如: - -```js -var shallowCompare = require('react-addons-shallow-compare'); -export class SampleComponent extends React.Component { - shouldComponentUpdate(nextProps, nextState) { - return shallowCompare(this, nextProps, nextState); - } - - render() { - return
                    foo
                    ; - } -} -``` - -`shallowCompare` 对当前的 `props` 和 `nextProps`对象 执行一个浅的相等检查,同样对于 `state` 和 `nextState`对象。 -它 通过迭代比较对象的keys 并在 对象的key值不严格相等时返回false 实现此功能. - -`shallowCompare` 返回 `true` 如果对 props 或 state的浅比较失败,因此组件应该更新。 -`shallowCompare` 返回 `false` 如果对 props 或 state的浅比较都通过了,因此组件不应该更新。 diff --git a/docs/docs/10.2-form-input-binding-sugar.it-IT.md b/docs/docs/10.2-form-input-binding-sugar.it-IT.md deleted file mode 100644 index a3d1662b39..0000000000 --- a/docs/docs/10.2-form-input-binding-sugar.it-IT.md +++ /dev/null @@ -1,114 +0,0 @@ ---- -id: two-way-binding-helpers-it-IT -title: Helper Per Binding Bidirezionali -permalink: docs/two-way-binding-helpers-it-IT.html -prev: animation-it-IT.html -next: test-utils-it-IT.html ---- - -`ReactLink` è una maniera semplice di esprimere binding bidirezionali con React. - -> Nota: -> -> Se hai poca esperienza del framework, nota che `ReactLink` non è necessario per molte applicazioni e dovrebbe essere utilizzato con cautela. - -In React, i dati fluiscono in una direzione: dal proprietario ai figli. Questo poiché i dati fluiscono in una sola direzione nel [modello di computazione di Von Neumann](https://en.wikipedia.org/wiki/Von_Neumann_architecture). Puoi pensare ad esso come "binding unidirezionale dei dati." - -Tuttavia, esistono parecchie applicazioni che richiedono di leggere dati e farli fluire nuovamente nel tuo programma. Ad esempio, quando sviluppi dei moduli, vorrai spesso aggiornare uno `state` di React quando ricevi un input dall'utente. O forse vuoi effettuare il layout in JavaScript e reagire ai cambiamenti nelle dimensioni di alcuni elementi DOM. - -In React, questo verrebbe implementato ascoltando un evento "change", leggendo la tua fonte di dati (solitamente il DOM) e chiamando `setState()` su uno dei tuoi componenti. "Chiudere il ciclo del flusso dei dati" esplicitamente conduce a programmi più comprensibili e mantenibili. Consulta [la nostra documentazione sui moduli](/react/docs/forms.html) per maggiori informazioni. - -Il binding bidirezionale -- assicurarsi implicitamente che alcuni valori nel DOM siano sempre consistenti con degli `state` in React -- è più conciso e supporta un'ampia varietà di applicazioni. Abbiamo fornito `ReactLink`: zucchero sintattico per impostare il pattern del ciclo del flusso di dati descritto in predecenza, ovvero "collegare" una fonte di dati con lo `state` di React. - -> Nota: -> -> `ReactLink` è soltanto uno strato di astrazione e convenzioni attorno al pattern `onChange`/`setState()`. Non cambia fondamentalmente la maniera in cui i dati fluiscono all'interno della tua applicazione React. - -## ReactLink: Prima e Dopo - -Ecco un semplice esempio di modulo che non utilizza `ReactLink`: - -```javascript -var NoLink = React.createClass({ - getInitialState: function() { - return {message: 'Ciao!'}; - }, - handleChange: function(event) { - this.setState({message: event.target.value}); - }, - render: function() { - var message = this.state.message; - return ; - } -}); -``` - -Ciò funziona molto bene e il flusso di dati è molto chiaro. Tuttavia, in presenza di un gran numero di campi del modulo può risultare assai prolisso. Utilizziamo `ReactLink` per risparmiarci la scrittura di un po' di codice: - -```javascript{2,7} -var WithLink = React.createClass({ - mixins: [React.addons.LinkedStateMixin], - getInitialState: function() { - return {message: 'Ciao!'}; - }, - render: function() { - return ; - } -}); -``` - -`LinkedStateMixin` aggiunge un metodo chiamato `linkState()` al tuo componente React. `linkState()` restituisce un oggetto `ReactLink` contenente il valore attuae dello stato React e una callback per cambiarlo. - -Gli oggetti `ReactLink` possono essere passati su e giù nell'albero come proprietà, quindi è facile (ed esplicito) impostare un binding bidirezionale tra un componente in profondità nella gerarchia e dello stato che si trova più in alto nella gerarchia. - -Nota che i checkbox hanno un comportamento speciale riguardo il loro attributo `value`, che è il valore che sarà inviato all'inoltro del modulo se il checkbox è spuntato (il valore predefinito è `on`). L'attributo `value` non è aggiornato quando il checkbox viene spuntato o deselezionato. Per i checkbox occorre usare `checkedLink` anziché `valueLink`: -``` - -``` - - -## Dietro le Quinte - -Ci sono due ambiti in `ReactLink`: il posto in cui crei l'istanza di `ReactLink` e il posto in cui la utilizzi. Per dimostrare quanto sia semplice usare `ReactLink`, riscriviamo ciascun ambito separatamente perché sia più esplicito. - -### ReactLink Senza LinkedStateMixin - -```javascript{5-7,9-12} -var WithoutMixin = React.createClass({ - getInitialState: function() { - return {message: 'Ciao!'}; - }, - handleChange: function(newValue) { - this.setState({message: newValue}); - }, - render: function() { - var valueLink = { - value: this.state.message, - requestChange: this.handleChange - }; - return ; - } -}); -``` - -Come puoi vedere, gli oggetti `ReactLink` sono semplici oggetti che hanno due proprietà: `value` e `requestChange`. `LinkedStateMixin` è altrettanto semplice: popola semplicemente questi campi con un valore da `this.state` e una callback che invoca `this.setState()`. - -### ReactLink Senza valueLink - -```javascript -var WithoutLink = React.createClass({ - mixins: [React.addons.LinkedStateMixin], - getInitialState: function() { - return {message: 'Ciao!'}; - }, - render: function() { - var valueLink = this.linkState('message'); - var handleChange = function(e) { - valueLink.requestChange(e.target.value); - }; - return ; - } -}); -``` - -La proprietà `valueLink` è anche abbastanza semplice. Gestisce semplicemente l'evento `onChange` e invoca `this.props.valueLink.requestChange()`, e inoltre utilizza `this.props.valueLink.value` anziché `this.props.value`. Tutto qua! diff --git a/docs/docs/10.2-form-input-binding-sugar.ja-JP.md b/docs/docs/10.2-form-input-binding-sugar.ja-JP.md deleted file mode 100644 index 9e456847d5..0000000000 --- a/docs/docs/10.2-form-input-binding-sugar.ja-JP.md +++ /dev/null @@ -1,114 +0,0 @@ ---- -id: two-way-binding-helpers -title: 2ウェイバインディングのヘルパ -permalink: docs/two-way-binding-helpers-ja-JP.html -prev: animation-ja-JP.html -next: test-utils-ja-JP.html ---- - -`ReactLink` はReactで2ウェイバインディングを表現する簡単な方法です。 - -> 注意: -> もしあなたがフレームワークについてあまりよく知らないのであれば、 `ReactLink` は多くのアプリケーションには必要なく、慎重に使うべきであることに注意してください。 - -Reactでは所有者から子要素へと、データの流れは一方向です。これはデータが[Von Neumannのコンピューティングモデル](https://en.wikipedia.org/wiki/Von_Neumann_architecture)によって一方向にのみ流れるからです。これを「1ウェイデータバインディング」だと考えることができます。 - -しかし、データやプログラムに戻る流れを読む必要が有るアプリケーションもたくさんあります。例えば、フォームを作る際に、ユーザのインプットを受け取った時には、Reactの `state` を更新したいと思うことはよくあるでしょう。または、JavaScriptでレイアウトを形作ったり、DOM要素のサイズの変化に反応したいと思うでしょう。 - -Reactでは、「変更」のイベントを検知し、データソース(普通はDOMです)を読み、コンポーネントのうちの1つの上で `setState()` を呼ぶことでこの要求を満たすことができます。「データフローのループを止めること」は理解しやすく、維持しやすいプログラムを明確に導きます。詳細な情報については、[フォームのドキュメント](/react/docs/forms-ja-JP.html)をご覧ください。 - -2ウェイバインディングはDOMの値が常にReactの `state` と一致していることを暗黙に強制しますが、簡潔で、多くの種類のアプリケーションをサポートします。上で説明されているような共通のデータフローループパターンのセットアップや、データソースをReactの `state` に「接続する」ための糖衣構文である `ReactLink` が提供されています。 - -> 注意: -> `ReactLink` は薄いラッパーであり、 `onChange`/`setState()` パターンにおける習慣です。Reactアプリケーションのデータフローの方法を根本から変えるようなものではありません。 - -## ReactLink: ビフォーアフター - -以下が、 `ReactLink` を使用しない単純なフォームの例です。 - -```javascript -var NoLink = React.createClass({ - getInitialState: function() { - return {message: 'Hello!'}; - }, - handleChange: function(event) { - this.setState({message: event.target.value}); - }, - render: function() { - var message = this.state.message; - return ; - } -}); -``` - -これはとてもよく動き、データがどう流れているかとても明確です。しかし、たくさんのフォームのフィールドがあった場合、少し冗長になります。以下のように、 `ReactLink` を使うことでタイピング量が少なくて済みます。 - -```javascript{2,7} -var WithLink = React.createClass({ - mixins: [React.addons.LinkedStateMixin], - getInitialState: function() { - return {message: 'Hello!'}; - }, - render: function() { - return ; - } -}); -``` - -`LinkedStateMixin` は `linkState()` と呼ばれるReactコンポーネントにメソッドを追加します。 -`linkState()` はReactのステータスの現在の値と、それを変更するコールバックを持った `ReactLink` オブジェクトを返します。 - -`ReactLink` オブジェクトはプロパティとして、木構造の上や下に渡される可能性があります。だから、階層の深い位置にいるコンポーネントと階層の高い位置にいるステータスの間の2ウェイバインディングをセットアップすることは簡単(で、明確)です。 - -チェックボックスはその `value` 属性に対しての特別な態度を持っていることに注意してください。それは、チェックボックスがチェックされている(デフォルトで `on` )場合にフォームのサブミットで送信される値です。 `value` 属性はチェックボックスがチェックされていても、チェックされていなくても、更新されません。チェックボックスについては、`valueLink` の代わりに、 `checkedLink` を使うべきです。以下のように。 - -``` - -``` - - -## フードの下 - -`ReactLink` には2つの側面があります。 `ReactLink` のインスタンスを作成する場所と、それを使う場所です。 `ReactLink` がどれだけ単純か証明するために、それぞれの側面を分けて、明確に再度記述してみましょう。 - -### LinkedStateMixinを使わないReactLink - -```javascript{5-7,9-12} -var WithoutMixin = React.createClass({ - getInitialState: function() { - return {message: 'Hello!'}; - }, - handleChange: function(newValue) { - this.setState({message: newValue}); - }, - render: function() { - var valueLink = { - value: this.state.message, - requestChange: this.handleChange - }; - return ; - } -}); -``` - -今まで見てきたように `ReactLink` オブジェクトは `value` と `requestChange` プロパティだけを持ったとても単純なオブジェクトです。そして、 `LinkedStateMixin` も同様に単純です。それらのフィールドを `this.state` の値と、 `this.setState()` を呼ぶコールバックで満たします。 - -### valueLinkを使わないReactLink - -```javascript -var WithoutLink = React.createClass({ - mixins: [React.addons.LinkedStateMixin], - getInitialState: function() { - return {message: 'Hello!'}; - }, - render: function() { - var valueLink = this.linkState('message'); - var handleChange = function(e) { - valueLink.requestChange(e.target.value); - }; - return ; - } -}); -``` - -`valueLink` プロパティも同様にとても単純です。単純に `onChange` イベントをハンドルし、 `this.props.valueLink.requestChange()` を呼び、 `this.props.value` の代わりに `this.props.valueLink.value` を使用します。それだけです! diff --git a/docs/docs/10.2-form-input-binding-sugar.ko-KR.md b/docs/docs/10.2-form-input-binding-sugar.ko-KR.md deleted file mode 100644 index a245721088..0000000000 --- a/docs/docs/10.2-form-input-binding-sugar.ko-KR.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -id: two-way-binding-helpers-ko-KR -title: 양방향 바인딩 핼퍼 -permalink: docs/two-way-binding-helpers-ko-KR.html -prev: animation-ko-KR.html -next: test-utils-ko-KR.html ---- - -`ReactLink`는 React에서 양방향 바인딩을 표현하는 쉬운 방법입니다. - -> 주의: -> -> 프레임워크를 새로 접하신다면, 대부분의 애플리케이션에서 `ReactLink`는 필요없고 신중히 사용하셔야 함을 알려드립니다. - -React에서 데이터 흐름은 소유주에서 자식으로의 단방향입니다. 이는 [폰 노이만 컴퓨팅 모델](http://ko.wikipedia.org/wiki/%ED%8F%B0_%EB%85%B8%EC%9D%B4%EB%A7%8C_%EA%B5%AC%EC%A1%B0)의 데이터가 단방향으로 흐르기 때문입니다. 이것을 "단방향 데이터 바인딩"으로 생각하셔도 됩니다. - -하지만 많은 애플리케이션에서 데이터를 요청해서 프로그램으로 돌려줍니다. 예를 들어, 폼을 개발한다면, 사용자 입력을 받았을 때 `state`를 바꾸거나, JavaScript안에서 레이아웃을 바꾸고 그에 따라 어떤 DOM 엘리먼트의 크기를 바꾸게 하고 싶을 수도 있습니다. - -React에서 이는 "change" 이벤트를 감시하고 데이터 소스(보통 DOM)에서 읽어 컴포넌트에서 `setState()`를 호출하는 식으로 할 수 있습니다. "데이터 흐름 반복을 제한"하면 더 이해하기 편하고, 쉽게 유지보수할 수 있는 프로그램이 만들어지는 것은 명확합니다. 더 자세한 내용은 [폼 문서](/react/docs/forms-ko-KR.html)를 확인하세요. - -양방향 바인딩(묵시적으로 DOM의 어떤 값은 React `state`와 일치하도록 강제하는 것)은 간결하기도 하고 다양한 애플리케이션을 지원 할 수 있습니다. React는 `ReactLink`를 제공합니다. 이는 위에서 설명한 일반적인 데이터 흐름 반복 패턴을 설정하거나, 어떤 데이터 소스를 React `state`로 "링크하는" 편의 문법입니다. - -> 주의: -> -> `ReactLink`는 얇은 레퍼고 `onChange`/`setState()`패턴 부분의 관례일 뿐입니다. React 애플리케이션에서의 데이터 흐름을 근본적으로 바꾸지는 않습니다. - -## ReactLink: 적용 전후 - -`ReactLink`를 사용하지 않는 간단한 폼 예제입니다. - -```javascript -var NoLink = React.createClass({ - getInitialState: function() { - return {message: '안녕!'}; - }, - handleChange: function(event) { - this.setState({message: event.target.value}); - }, - render: function() { - var message = this.state.message; - return ; - } -}); -``` - -이것은 정말 잘 동작하고, 데이터가 어떻게 흐르는지 매우 명확하게 보여지지만, 폼필드가 많을 경우 약간 장황해 질 수 있습니다. 타이핑을 줄이기 위해 `ReactLink`를 사용해 보겠습니다. - -```javascript{4,9} -var LinkedStateMixin = require('react-addons-linked-state-mixin'); - -var WithLink = React.createClass({ - mixins: [LinkedStateMixin], - getInitialState: function() { - return {message: 'Hello!'}; - }, - render: function() { - return ; - } -}); -``` - -`LinkedStateMixin`는 React 컴포넌트에 `linkState()`라는 메서드를 추가합니다. `linkState()`는 React state의 현재 값과 그것을 변경할 때의 콜백을 가지는 `ReactLink` 객체를 리턴합니다. - -`ReactLink` 객체는 props로 트리의 위나 아래로 넘길 수 있어서, 쉽고 명확하게 계층구조에서 깊이 있는 컴포넌트와 높이 있는 state 사이의 양방향 바인딩을 설정할 수 있습니다. - -checkbox의 `value` 어트리뷰트는 다른 것과 다르게 checkbox가 체크되었을 때 폼 submit에 값이 전달되는 것에 주의하세요.(기본값 `on`) 그래서 `value` 어트리뷰트는 checkbox가 체크되거나 해제될 때 업데이트되지 않습니다. checkbox에서는 `valueLink`대신 `checkedLink`를 사용하셔야 합니다. -``` - -``` - -## 내부 구조 - -`ReactLink`에는 크게 인스턴스를 생성하는 면과 사용하는 면이 있습니다. `ReactLink`가 얼마나 간단한지 확인하기 위해, 이 부분들을 보다 명시적으로 고쳐 봅시다. - -### LinkedStateMixin 없이 ReactLink 쓰기 - -```javascript{5-7,9-12} -var WithoutMixin = React.createClass({ - getInitialState: function() { - return {message: 'Hello!'}; - }, - handleChange: function(newValue) { - this.setState({message: newValue}); - }, - render: function() { - var valueLink = { - value: this.state.message, - requestChange: this.handleChange - }; - return ; - } -}); -``` - -보시다시피, `ReactLink` 객체는 `value`와 `requestChange` prop만 가지는 매우 간단한 객체입니다. `LinkedStateMixin`도 간단합니다. 그냥 `this.state`의 값과 `this.setState()`에서 호출되는 콜백을 필드로 가질 뿐입니다. - -### valueLink 없이 ReactLink 쓰기 - -```javascript -var LinkedStateMixin = require('react-addons-linked-state-mixin'); - -var WithoutLink = React.createClass({ - mixins: [LinkedStateMixin], - getInitialState: function() { - return {message: 'Hello!'}; - }, - render: function() { - var valueLink = this.linkState('message'); - var handleChange = function(e) { - valueLink.requestChange(e.target.value); - }; - return ; - } -}); -``` - -`valueLink` prop도 간단합니다. 단순히 `onChange` 이벤트를 처리하고 `this.props.valueLink.requestChange()`를 호출하고 `this.props.value`대신 `this.props.valueLink.value`를 사용합니다. 그게 다에요! diff --git a/docs/docs/10.2-form-input-binding-sugar.zh-CN.md b/docs/docs/10.2-form-input-binding-sugar.zh-CN.md deleted file mode 100644 index 5bb3f31215..0000000000 --- a/docs/docs/10.2-form-input-binding-sugar.zh-CN.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -id: two-way-binding-helpers-zh-CN -title: 双向绑定辅助 -permalink: docs/two-way-binding-helpers-zh-CN.html -prev: animation-zh-CN.html -next: test-utils-zh-CN.html ---- - -`ReactLink` 是一个用React表达双向绑定的简单方法。 - -> 注意: -> -> 在 React v15 中 ReactLink 被弃用了。推荐明确的设置值和变动的处理,而不是使用 ReactLink。 - -在React里,数据单向流动: 从拥有者到子级。这是因为数据只单向流动[the Von Neumann model of computing](https://en.wikipedia.org/wiki/Von_Neumann_architecture)。你可以把它想象为 “单向数据绑定”。 - -然而,有很多应用需要你去读某些数据并回流他们到你的程序。例如,当开发forms,你会常常想更新一些React `state` 当你收到用户输入的时候。或者也许你想在JavaScript完成布局并相应一些DOM元素大小的变化。 - -在React里,你可以用监听 "change" 事件来实现它,从你的数据源(通常是DOM)读取并在你的某个组件调用 `setState()` 。明确的"Closing the data flow loop" 致使了更容易理解和维护的程序。更多信息见[our forms documentation](/react/docs/forms.html). - -双向绑定 -- 隐含的强迫DOM里的某些值总是和某些React `state` 同步 -- 简洁并支持大量多样的应用。 我们提供了 `ReactLink`:设置如上描述的通用数据回流模式的语法糖,或者 "linking" 某些数据结构到 React `state`. - -> 注意: -> -> `ReactLink` 只是一层对 `onChange`/`setState()` 模式的薄包装。它没有根本性的改变你的React应用里数据如何流动。 - -## ReactLink: 之前和之后 - -这里有一个简单的 不用 `ReactLink` 的 form 例子: - -```javascript -var NoLink = React.createClass({ - getInitialState: function() { - return {message: 'Hello!'}; - }, - handleChange: function(event) { - this.setState({message: event.target.value}); - }, - render: function() { - var message = this.state.message; - return ; - } -}); -``` - -这个工作的很好并且数据如何流动很清晰,然而,当有大量的 form fields时,可能会有些冗长。让我们使用 `ReactLink` 来节省我们的输入: - -```javascript{4,9} -var LinkedStateMixin = require('react-addons-linked-state-mixin'); - -var WithLink = React.createClass({ - mixins: [LinkedStateMixin], - getInitialState: function() { - return {message: 'Hello!'}; - }, - render: function() { - return ; - } -}); -``` - -`LinkedStateMixin` 添加了一个 `linkState()` 方法到你的React组件。`linkState()` 返回一个 `ReactLink` 包含当前React state值的对象和一个改变它的回调函数。 - -`ReactLink` 对象可以作为props在树中上下传递,所以很容易(显示的)在深层次的组件和高层次的state之间 设置双向绑定。 - -注意 checkboxes 有一个关于他们 `value` 属性的特殊行为,这个行为是 如果checkbox被选中 值会在表单提交时被发送。 `value` 不会 checkbox 选中或是不选中时更新。对于checkboxes,你应该用`checkedLink` 代替 `valueLink`: -``` - -``` - -## 引擎盖下 - -这里对 `ReactLink`有两方面:创建`ReactLink`的实例以及使用它的地方。为了证明`ReactLink`有多简单,让我们重写两方面一边更好的理解。 - -### ReactLink Without LinkedStateMixin - -```javascript{5-7,9-12} -var WithoutMixin = React.createClass({ - getInitialState: function() { - return {message: 'Hello!'}; - }, - handleChange: function(newValue) { - this.setState({message: newValue}); - }, - render: function() { - var valueLink = { - value: this.state.message, - requestChange: this.handleChange - }; - return ; - } -}); -``` - -正如你所见,`ReactLink`对象是非常简单,只有`value`和`requestChange`属性.并且`LinkStateMixin`也很简单:它只是作用(populates)于`this.state`的元素值并且回调名为`this.setState()`的函数. - -### ReactLink Without valueLink - -```javascript -var LinkedStateMixin = require('react-addons-linked-state-mixin'); - -var WithoutLink = React.createClass({ - mixins: [LinkedStateMixin], - getInitialState: function() { - return {message: 'Hello!'}; - }, - render: function() { - var valueLink = this.linkState('message'); - var handleChange = function(e) { - valueLink.requestChange(e.target.value); - }; - return ; - } -}); -``` - -对于`valueLink`的属性同样也很简单,它只是简单的处理`onChange`事件,调用`this.props.valueLink.requestChange()`的时候也使用`this.props.valueLink.requestChange()`代替`this.props.value`.这就是双向绑定! diff --git a/docs/docs/10.3-class-name-manipulation.it-IT.md b/docs/docs/10.3-class-name-manipulation.it-IT.md deleted file mode 100644 index 7fb9da7660..0000000000 --- a/docs/docs/10.3-class-name-manipulation.it-IT.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -id: class-name-manipulation-it-IT -title: Manipolazione del Nome di Classe -permalink: docs/class-name-manipulation-it-IT.html -prev: two-way-binding-helpers-it-IT.html -next: test-utils-it-IT.html ---- - -> NOTA: -> -> Questo modulo esiste adesso in forma separata come [JedWatson/classnames](https://github.com/JedWatson/classnames) ed è indipendente da React. Questo add-on verrà quindi rimosso nell'immediato futuro. - -`classSet()` è una elegante utility per manipolare facilmente la stringa dell'attributo `class` del DOM. - -Ecco uno scenario comune e la sua soluzione senza `classSet()`: - -```javascript -// all'interno di un componente React `` -render: function() { - var classString = 'message'; - if (this.props.isImportant) { - classString += ' message-important'; - } - if (this.props.isRead) { - classString += ' message-read'; - } - // 'message message-important message-read' - return
                    Fantastico, vediamoci lì.
                    ; -} -``` - -Questo può facilmente diventare noioso, in quanto assegnare stringhe per nomi di classi può essere difficile da leggere e soggetto ad errori. `classSet()` risolve questo problema: - -```javascript -render: function() { - var cx = React.addons.classSet; - var classes = cx({ - 'message': true, - 'message-important': this.props.isImportant, - 'message-read': this.props.isRead - }); - // same final string, but much cleaner - return
                    Fantastico, vediamoci lì.
                    ; -} -``` - -Quando usi `classSet()`, passa un oggetto le cui chiavi sono i nomi di classe CSS di cui potresti o meno avere bisogno. Valori di verità risulteranno nell'inclusione della chiave nella stringa risultante. - -`classSet()` ti permette inoltre di passare nomi di classe che devono essere concatenati come argomenti: - -```javascript -render: function() { - var cx = React.addons.classSet; - var importantModifier = 'message-important'; - var readModifier = 'message-read'; - var classes = cx('message', importantModifier, readModifier); - // Final string is 'message message-important message-read' - return
                    Fantastico, vediamoci lì.
                    ; -} -``` - -Niente più hack per concatenare le stringhe! diff --git a/docs/docs/10.3-class-name-manipulation.ja-JP.md b/docs/docs/10.3-class-name-manipulation.ja-JP.md deleted file mode 100644 index ecbde74480..0000000000 --- a/docs/docs/10.3-class-name-manipulation.ja-JP.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -id: class-name-manipulation -title: クラス名の操作 -permalink: docs/class-name-manipulation-ja-JP.html -prev: two-way-binding-helpers-ja-JP.html -next: test-utils-ja-JP.html ---- - -> 注意: -> このモジュールは現在[JedWatson/classnames](https://github.com/JedWatson/classnames)に独立して存在しており、Reactは変更を検知していません。したがって、こちらは将来削除される予定です。 - -`classSet()` はDOMの `class` 文字列を簡単に操作するすっきりとしたユーティリティです。 - -以下は、 `classSet()` を使用しない共通なシナリオと解決策です。 - -```javascript -// `` などの中のReactコンポーネント -render: function() { - var classString = 'message'; - if (this.props.isImportant) { - classString += ' message-important'; - } - if (this.props.isRead) { - classString += ' message-read'; - } - // 'message message-important message-read' - return
                    Great, I'll be there.
                    ; -} -``` - -上記は、クラス名を文字列として渡しているので、面倒で、読みにくく、エラーが発生しやすくなります。以下のように、 `classSet()` を使用するとこの問題が解決します。 - -```javascript -render: function() { - var cx = React.addons.classSet; - var classes = cx({ - 'message': true, - 'message-important': this.props.isImportant, - 'message-read': this.props.isRead - }); - // 同様に最終的には文字列になりますが、クリアにはなります - return
                    Great, I'll be there.
                    ; -} -``` - - `classSet()` を使用する際には、キーと、必要であったり、必要でないCSSのクラス名をオブジェクトとして渡してください。値が真であるものはキーとなり、最終的には文字列の一部になります。 - -`classSet()` もまた、以下のように連結した文字列の引数としてクラス名を渡します。 - -```javascript -render: function() { - var cx = React.addons.classSet; - var importantModifier = 'message-important'; - var readModifier = 'message-read'; - var classes = cx('message', importantModifier, readModifier); - // 最終的な文字列は 'message message-important message-read' - return
                    Great, I'll be there.
                    ; -} -``` - -文字列の連結を手で書くのはやめましょう! diff --git a/docs/docs/10.3-class-name-manipulation.ko-KR.md b/docs/docs/10.3-class-name-manipulation.ko-KR.md deleted file mode 100644 index 6e11d8d6ea..0000000000 --- a/docs/docs/10.3-class-name-manipulation.ko-KR.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -id: class-name-manipulation-ko-KR -title: 클래스 이름 조작 -permalink: docs/class-name-manipulation-ko-KR.html -prev: two-way-binding-helpers-ko-KR.html -next: test-utils-ko-KR.html ---- - -> 주의: -> -> 이 모듈은 폐기예정입니다. 대신 [JedWatson/classnames](https://github.com/JedWatson/classnames)를 사용하세요. - -`classSet()`은 간단히 DOM `class` 문자열을 조작하는 편리한 도구입니다. - -일반적으로 있을법한 경우와 `classSet()`을 사용하지 않았을 때의 처리법을 보시죠. - -```javascript -// 어떤 `` React 컴포넌트의 안쪽 -render: function() { - var classString = 'message'; - if (this.props.isImportant) { - classString += ' message-important'; - } - if (this.props.isRead) { - classString += ' message-read'; - } - // 'message message-important message-read' - return
                    좋아요, 거기서 봅시다.
                    ; -} -``` - -이것은 순식간에 장황해질 수 있습니다. 클래스 이름 문자열은 읽기 어렵고 에러가 발생하기도 쉽죠. `classSet()`가 이 문제를 해결할 수 있습니다. - -```javascript -render: function() { - var cx = React.addons.classSet; - var classes = cx({ - 'message': true, - 'message-important': this.props.isImportant, - 'message-read': this.props.isRead - }); - // 최종 문자열은 동일하지만, 훨씬 깔끔함 - return
                    좋아요, 거기서 봅시다.
                    ; -} -``` - -`classSet()`을 사용할 때 사용할지 안할지 잘 모르는 CSS 클래스 이름 키와 함께 객체를 전달합니다. true로 간주되는(Truthy) 값은 키를 결과 문자열의 일부로 만듭니다. - -`classSet()`은 클래스 이름을 인자로 넘겨 연결되게 할 수도 있습니다. - -```javascript -render: function() { - var cx = React.addons.classSet; - var importantModifier = 'message-important'; - var readModifier = 'message-read'; - var classes = cx('message', importantModifier, readModifier); - // 최종 문자열은 'message message-important message-read' - return
                    좋아요, 거기서 봅시다.
                    ; -} -``` - -복잡한 문자열 연결은 이제 안하셔도 됩니다! diff --git a/docs/docs/10.3-class-name-manipulation.md b/docs/docs/10.3-class-name-manipulation.md deleted file mode 100644 index ad529525c1..0000000000 --- a/docs/docs/10.3-class-name-manipulation.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -id: class-name-manipulation -title: Class Name Manipulation -permalink: docs/class-name-manipulation.html -prev: two-way-binding-helpers.html -next: test-utils.html ---- - -> NOTE: -> -> This module has been deprecated; use [JedWatson/classnames](https://github.com/JedWatson/classnames) instead. diff --git a/docs/docs/10.3-class-name-manipulation.zh-CN.md b/docs/docs/10.3-class-name-manipulation.zh-CN.md deleted file mode 100644 index d3ab80f431..0000000000 --- a/docs/docs/10.3-class-name-manipulation.zh-CN.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -id: class-name-manipulation-zh-CN -title: 类名操纵 -permalink: docs/class-name-manipulation-zh-CN.html -prev: two-way-binding-helpers-zh-CN.html -next: test-utils-zh-CN.html ---- - -> NOTE: -> -> 此模块已被弃用; 用 [JedWatson/classnames](https://github.com/JedWatson/classnames) 替代. diff --git a/docs/docs/10.4-test-utils.it-IT.md b/docs/docs/10.4-test-utils.it-IT.md deleted file mode 100644 index 0b86024655..0000000000 --- a/docs/docs/10.4-test-utils.it-IT.md +++ /dev/null @@ -1,233 +0,0 @@ ---- -id: test-utils-it-IT -title: Utilità di Test -permalink: docs/test-utils-it-IT.html -prev: two-way-binding-helpers-it-IT.html -next: clone-with-props-it-IT.html ---- - -`React.addons.TestUtils` semplifica la validazione dei componenti React nel framework di test di tua scelta (noi utilizziamo [Jest](https://facebook.github.io/jest/)). - -### Simulate - -```javascript -Simulate.{eventName}( - DOMElement element, - [object eventData] -) -``` - -Simula l'inoltro di un evento su un nodo DOM con dei dati dell'evento opzionali `eventData`. **Questa è probabilmente l'utilità più essenziale in `ReactTestUtils`.** - -**Cliccare un elemento** - -```javascript -var node = ReactDOM.findDOMNode(this.refs.button); -React.addons.TestUtils.Simulate.click(node); -``` - -**Cambiare il valore di un campo di input e in seguito premere INVIO** - -```javascript -var node = ReactDOM.findDOMNode(this.refs.input); -node.value = 'giraffe'; -React.addons.TestUtils.Simulate.change(node); -React.addons.TestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13}); -``` - -*nota che dovrai fornire tu stesso ciascuna proprietà dell'evento utilizzata nel tuo componente (ad es. keyCode, which, etc...) in quanto React non crea alcuna di esse per te* - -`Simulate` possiede un metodo per ciascun evento che React comprende. - -### renderIntoDocument - -```javascript -ReactComponent renderIntoDocument( - ReactElement instance -) -``` - -Effettua il rendering di un componente in un nodo DOM staccato dal documento. **Questa funzione richiede la presenza del DOM.** - -### mockComponent - -```javascript -object mockComponent( - function componentClass, - [string mockTagName] -) -``` - -Passa il mock di un componente a questo metodo per aumentarlo con metodi utili che gli permettono di essere utilizzato come un componente React fantoccio. Anziché essere visualizzato come al solito, il componente diventerà un semplice `
                    ` (o qualsiasi altro tag se fornito come valore di `mockTagName`) contenente ciascun figlio fornito. - -### isElement - -```javascript -boolean isElement( - ReactElement element -) -``` - -Restituisce `true` se `element` è un qualunque ReactElement. - -### isElementOfType - -```javascript -boolean isElementOfType( - ReactElement element, - function componentClass -) -``` - -Restituisce `true` se `element` è un ReactElement il cui tipo è la classe React `componentClass`. - -### isDOMComponent - -```javascript -boolean isDOMComponent( - ReactComponent instance -) -``` - -Restituisce `true` se `instance` è un componente DOM (come ad esempio `
                    ` o ``). - -### isCompositeComponent - -```javascript -boolean isCompositeComponent( - ReactComponent instance -) -``` - -Restituisce `true` se `instance` è un componente composito (creato tramite `React.createClass()`). - -### isCompositeComponentWithType - -```javascript -boolean isCompositeComponentWithType( - ReactComponent instance, - function componentClass -) -``` - -Restituisce `true` se `instance` è un componente composito (creato tramite `React.createClass()`) il cui tipo è una classe React dal nome `componentClass`. - -### findAllInRenderedTree - -```javascript -array findAllInRenderedTree( - ReactComponent tree, - function test -) -``` - -Attraversa tutti i componenti in `tree` e accumula tutti i componenti per i quali `test(component)` è `true`. Non è molto utile usata da sola, ma diventa ptente se usata come primitiva per altre utilità di test. - -### scryRenderedDOMComponentsWithClass - -```javascript -array scryRenderedDOMComponentsWithClass( - ReactComponent tree, string className -) -``` - -Trova tutte le istanze di componenti nell'albero visualizzato che sono componenti DOM il cui nome di classe corrisponde a `className`. - -### findRenderedDOMComponentWithClass - -```javascript -ReactComponent findRenderedDOMComponentWithClass( - ReactComponent tree, - string className -) -``` - -Simile a `scryRenderedDOMComponentsWithClass()` ma si aspetta di trovare un solo risultato, e restituisce quel solo risultato, oppure lancia un'eccezione se viene trovato qualunque altro numero di occorrenze diverso da uno. - -### scryRenderedDOMComponentsWithTag - -```javascript -array scryRenderedDOMComponentsWithTag( - ReactComponent tree, - string tagName -) -``` - -Trova tutte le istanze di componenti nell'albero visualizzato che sono componenti DOM il cui nome di tag corrisponde a `tagName`. - -### findRenderedDOMComponentWithTag - -```javascript -ReactComponent findRenderedDOMComponentWithTag( - ReactComponent tree, - string tagName -) -``` - -Simile a `scryRenderedDOMComponentsWithTag()` ma si aspetta di trovare un solo risultato, e restituisce quel solo risultato, oppure lancia un'eccezione se viene trovato qualunque altro numero di occorrenze diverso da uno. - -### scryRenderedComponentsWithType - -```javascript -array scryRenderedComponentsWithType( - ReactComponent tree, - function componentClass -) -``` - -Trova tutte le istanze di componenti il cui tipo corrisponde a `componentClass`. - -### findRenderedComponentWithType - -```javascript -ReactComponent findRenderedComponentWithType( - ReactComponent tree, function componentClass -) -``` - -Simile a `scryRenderedComponentsWithType()` si aspetta di trovare un solo risultato, oppure lancia un'eccezione se viene trovato qualunque altro numero di occorrenze diverso da uno. - - -## Rendering superficiale - -Il rendering superficiale è una caratteristica sperimentale che ti permette di effettuare il rendering di un componente "ad un livello di profondità" e asserire dei fatti su ciò che viene restituito dal suo metodo render, senza preoccuparti del comportamento dei componenti figli, i quali non sono né istanziati né viene effettuato il rendering. Questo non richiede la presenza di un DOM. - -```javascript -ReactShallowRenderer createRenderer() -``` - -Chiama questo metodo nei tuoi test per creare un renderer superficiale. Puoi pensare ad esso come un "luogo" in cui effettuare il rendering del componente che stai validando, dove può rispondere ad eventi e aggiornarsi. - -```javascript -shallowRenderer.render( - ReactElement element -) -``` - -Simile a `ReactDOM.render`. - -```javascript -ReactComponent shallowRenderer.getRenderOutput() -``` - -Dopo che `render` è stato chiamato, restituisce un output di cui è stato effettuato un rendering superficiale. Puoi quindi iniziare ad asserire fatti sull'output. Ad esempio, se il metodo render del tuo componente resituisce: - -```javascript -
                    - Titolo - -
                    -``` - -Allora puoi asserire: - -```javascript -result = renderer.getRenderOutput(); -expect(result.type).toBe('div'); -expect(result.props.children).toEqual([ - Titolo, - -]); -``` - -La validazione superficiale ha al momento alcune limitazioni, in particolare non supporta i riferimenti. Stiamo rilasciando questa caratteristica in anticipo e gradiremmo ascoltare il parere della comunità React per la direzione in cui debba evolvere. diff --git a/docs/docs/10.4-test-utils.ja-JP.md b/docs/docs/10.4-test-utils.ja-JP.md deleted file mode 100644 index 37e8daafff..0000000000 --- a/docs/docs/10.4-test-utils.ja-JP.md +++ /dev/null @@ -1,183 +0,0 @@ ---- -id: test-utils -title: テストユーティリティ -permalink: docs/test-utils-ja-JP.html -prev: two-way-binding-helpers-ja-JP.html -next: clone-with-props-ja-JP.html ---- - -`React.addons.TestUtils` は選んだテストフレームワーク(私たちは[Jest](https://facebook.github.io/jest/)を使っています)において、Reactのコンポーネントをテストすることを簡単にします。 - -### Simulate - -```javascript -Simulate.{eventName}(DOMElement element, object eventData) -``` - -オプションの `eventData` であるイベントデータと共に、DOMノードの上でイベントのディスパッチをシミュレートします。 **これは `ReactTestUtils` の中で最も有用なユーティリティでしょう。** - -使用例: - -```javascript -var node = ReactDOM.findDOMNode(this.refs.input); -React.addons.TestUtils.Simulate.click(node); -React.addons.TestUtils.Simulate.change(node, {target: {value: 'Hello, world'}}); -React.addons.TestUtils.Simulate.keyDown(node, {key: "Enter"}); -``` - -`Simulate` はReactが理解出来る全てのイベントのためのメソッドを持っています。 - -### renderIntoDocument - -```javascript -ReactComponent renderIntoDocument(ReactElement instance) -``` - -コンポーネントをドキュメントの中で分離したDOMノードにレンダリングします。 **この関数はDOMを必要とします。** - - -### mockComponent - -```javascript -object mockComponent(function componentClass, string? mockTagName) -``` - -有効なダミーのReactのコンポーネントとして使われることを許可するメソッドと共にこれを増強させるためにモックとなったコンポーネントモジュールをこのメソッドに渡してください。いつものようにレンダリングされる代わりに、コンポーネントは単純で、提供された子要素はどんなものでも含む `
                    ` (`mockTagName` が提供されている場合はそのタグ)になるでしょう。 - -### isElement - -```javascript -boolean isElement(ReactElement element) -``` - -`element` が何かしらのReactElementだった場合に `true` を返します。 - -### isElementOfType - -```javascript -boolean isElementOfType(ReactElement element, function componentClass) -``` - -`element` がReactの `componentClass` 型であるReactElementだった場合に `true` を返します。 - -### isDOMComponent - -```javascript -boolean isDOMComponent(ReactComponent instance) -``` - -`instance` がDOMのコンポーネントだった場合に `true` を返します( `
                    ` や `` のように)。 - -### isCompositeComponent - -```javascript -boolean isCompositeComponent(ReactComponent instance)` -``` - -`instance` が複合的なコンポーネントだった場合に `true` を返します(`React.createClass()` で作成されるような)。 - -### isCompositeComponentWithType - -```javascript -boolean isCompositeComponentWithType(ReactComponent instance, function componentClass) -``` - -`instance` が複合的なコンポーネントだった場合に `true` を返します(`React.createClass()` で作成され、型がReactの `componentClass` であるような)。 - -### findAllInRenderedTree - -```javascript -array findAllInRenderedTree(ReactComponent tree, function test) -``` - -`tree` の中の全てのコンポーネントや `test(component)` が `true` となる蓄積された全てのコンポーネントを検討します。これはこれだけでは有用ではありませんが、他のテストユーティリティの根本として使われます。 - -### scryRenderedDOMComponentsWithClass - -```javascript -array scryRenderedDOMComponentsWithClass(ReactComponent tree, string className) -``` - -レンダリングされたツリーの中で、DOMコンポーネントであり、クラス名が `className` にマッチする、コンポーネントの全てのインスタンスを見つけます。 - -### findRenderedDOMComponentWithClass - -```javascript -ReactComponent findRenderedDOMComponentWithClass(ReactComponent tree, string className) -``` - -`scryRenderedDOMComponentsWithClass()` に似ていますが、結果が1つであること、それを返すこと、またはマッチする個数が1個以外だった場合に例外を投げることを予期します。 - -### scryRenderedDOMComponentsWithTag - -```javascript -array scryRenderedDOMComponentsWithTag(ReactComponent tree, string tagName) -``` - -レンダリングされたツリーの中で、DOMコンポーネントであり、タグ名が `tagName` にマッチする、コンポーネントの全てのインスタンスを見つけます。 - -### findRenderedDOMComponentWithTag - -```javascript -ReactComponent findRenderedDOMComponentWithTag(ReactComponent tree, string tagName) -``` - -`scryRenderedDOMComponentsWithTag()` に似ていますが、結果が1つであること、それを返すこと、またはマッチする個数が1個以外だった場合に例外を投げることを予期します。 - -### scryRenderedComponentsWithType - -```javascript -array scryRenderedComponentsWithType(ReactComponent tree, function componentClass) -``` - -型名が `componentClass` と同様である、コンポーネントの全てのインスタンスを見つけます。 - -### findRenderedComponentWithType - -```javascript -ReactComponent findRenderedComponentWithType(ReactComponent tree, function componentClass) -``` - -`scryRenderedComponentsWithType()` と同じですが、結果が1つであること、それを返すこと、またはマッチする個数が1個以外だった場合に例外を投げることを予期します。 - -## Shallow rendering - -シャローレンダリングは"第一段階の深さ"であるコンポーネントをレンダリングすることを強制し、レンダリングメソッドが返すものについての事実をアサートし、インスタンスを生成したり、レンダリングされたりしない子のコンポーネントの振る舞いについては関心しない実験的な特徴です。これはDOMを必要としません。 - -```javascript -ReactShallowRenderer createRenderer() -``` - -シャローレンダラーを作成するにはこれをテストの中で呼んでください。これをあなたがテストするコンポーネントをレンダリングする場所であると考えることができます。この場所はイベントに返答したり、これ自身を更新したりできます。 - -```javascript -shallowRenderer.render(ReactElement element) -``` - -`ReactDOM.render` に同様。 - -```javascript -ReactComponent shallowRenderer.getRenderOutput() -``` - -`render` が呼ばれた後、浅くレンダリングされた出力を返します。その後、その出力に関しての事実をアサートすることができます。例えば、以下のように、コンポーネントのレンダリングメソッドが返してきた場合は、 - -```javascript -
                    - Title - -
                    -``` - -以下のように、アサートできます。 - -```javascript -result = renderer.getRenderOutput(); -expect(result.type).toBe('div'); -expect(result.props.children).toEqual([ - Title, - -]); -``` - -シャローテスティングは現在、制限があります。はっきり言うと、参照をサポートしていません。私たちは、この特徴を早めにリリースし、これが、どのように進化していくか、Reactのコミュニティのフィードバックを評価するつもりです。 diff --git a/docs/docs/10.4-test-utils.ko-KR.md b/docs/docs/10.4-test-utils.ko-KR.md deleted file mode 100644 index e9ac34e765..0000000000 --- a/docs/docs/10.4-test-utils.ko-KR.md +++ /dev/null @@ -1,236 +0,0 @@ ---- -id: test-utils-ko-KR -title: 테스트 유틸리티 -permalink: docs/test-utils-ko-KR.html -prev: two-way-binding-helpers-ko-KR.html -next: clone-with-props-ko-KR.html ---- - -`ReactTestUtils`는 선택한 테스트 프레임워크(React는 [Jest](https://facebook.github.io/jest/)를 사용)에서 React 컴포넌트를 테스트하기 쉽게 합니다. - -``` -var ReactTestUtils = require('react-addons-test-utils'); -``` - -### Simulate - -```javascript -Simulate.{eventName}( - DOMElement element, - [object eventData] -) -``` - -DOM 노드에 이벤트 디스패치하는 것을 시뮬레이트합니다. 선택적으로 `eventData`를 통해 이벤트 데이터도 처리할 수 있습니다. **아마 `ReactTestUtils`에서 가장 유용한 유틸리티일 것 입니다.** - -**엘리먼트 클릭** - -```javascript -// -var node = this.refs.button; -ReactTestUtils.Simulate.click(node); -``` - -**입력 필드의 값을 변경하고 엔터 누르기.** - -```javascript -// -var node = this.refs.input; -node.value = 'giraffe'; -ReactTestUtils.Simulate.change(node); -ReactTestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13}); -``` - -*컴포넌트에서 사용할 이벤트 프로퍼티(예를 들어 keyCode, which, 등등...)는 React에서 만들어 주지 않으므로 직접 제공해야 합니다.* - -`Simulate`에는 React가 이해하는 모든 이벤트에 대해 메소드가 있습니다. - -### renderIntoDocument - -```javascript -ReactComponent renderIntoDocument( - ReactElement instance -) -``` - -문서의 detach된 DOM 노드에 컴포넌트를 렌더합니다. **이 기능은 DOM을 필요로 합니다.** - -> 주의: -> -> React를 임포트하기 **전에** `window`, `window.document`, `window.document.createElement`을 전역적으로 사용가능하게 해두어야 합니다. 아니면 React는 DOM과 `setState`같은 메소드가 동작하지 않는다고 생각할 수 있습니다. - -### mockComponent - -```javascript -object mockComponent( - function componentClass, - [string mockTagName] -) -``` - -목 컴포넌트 모듈을 이 메소드에 넘겨 더미 React 컴포넌트로 사용할 수 있도록 합니다. 이 더미는 유용한 메소드와 함께 사용해 기능을 보강할 수 있습니다. 일반적인 렌더링과는 다르게, 컴포넌트는 제공된 자식을 포함하는 평범한 `
                    `가 됩니다. (`mockTagName`을 통해 div가 아닌 다른 태그를 지정해 줄 수도 있습니다.) - -### isElement - -```javascript -boolean isElement( - ReactElement element -) -``` - -`element`가 ReactElement면 `true`를 리턴합니다. - -### isElementOfType - -```javascript -boolean isElementOfType( - ReactElement element, - function componentClass -) -``` - -`element`가 React `componentClass` 타입인 ReactElement면 `true`를 리턴합니다. - -### isDOMComponent - -```javascript -boolean isDOMComponent( - ReactComponent instance -) -``` - -`instance`가 (`
                    `나 ``같은) DOM 컴포넌트면 `true`를 리턴합니다. - -### isCompositeComponent - -```javascript -boolean isCompositeComponent(ReactComponent instance)` -``` - -`instance`가 (`React.createClass()`로 생성된) 복합 컴포넌트면 `true`를 리턴합니다. - -### isCompositeComponentWithType - -```javascript -boolean isCompositeComponentWithType( - ReactComponent instance, - function componentClass -) -``` - -`instance`가 (`React.createClass()`로 생성된) 복합 컴포넌트고 React `componentClass` 타입이면 `true`를 리턴합니다. - -### findAllInRenderedTree - -```javascript -array findAllInRenderedTree( - ReactComponent tree, - function test -) -``` - -`tree`안의 모든 컴포넌트에서 `test(component)`가 `true`인 모든 컴포넌트를 모읍니다. 이것만으로는 그렇게 유용하지 않습니다만, 다른 테스트 유틸와 같이 사용합니다. - -### scryRenderedDOMComponentsWithClass - -```javascript -array scryRenderedDOMComponentsWithClass( - ReactComponent tree, string className -) -``` -렌더된 트리의 모든 컴포넌트 인스턴스 중에서 클래스 이름이 `className`인 DOM 컴포넌트들을 찾습니다. - -### findRenderedDOMComponentWithClass - -```javascript -ReactComponent findRenderedDOMComponentWithClass(ReactComponent tree, string className) -``` - -`scryRenderedDOMComponentsWithClass()`와 비슷하지만 하나의 결과만 기대될 때 사용합니다. 하나의 결과를 리턴하거나 한개 이상의 결과가 나온 경우에는 예외를 던집니다. - -### scryRenderedDOMComponentsWithTag - -```javascript -array scryRenderedDOMComponentsWithTag( - ReactComponent tree, - string tagName -) -``` - -렌더된 트리의 모든 컴포넌트 인스턴스중에서 태그 이름이 `tagName`인 DOM 컴포넌트들을 찾습니다. - -### findRenderedDOMComponentWithTag - -```javascript -ReactComponent findRenderedDOMComponentWithTag( - ReactComponent tree, - string tagName -) -``` - -`scryRenderedDOMComponentsWithTag()`와 비슷하지만 하나의 결과만 기대될 때 사용합니다. 하나의 결과를 리턴하거나 한개 이상의 결과가 나온 경우에는 예외를 던집니다. - -### scryRenderedComponentsWithType - -```javascript -array scryRenderedComponentsWithType( - ReactComponent tree, - function componentClass -) -``` - -타입이 `componentClass`인 모든 컴포넌트 인스턴스를 찾습니다. - -### findRenderedComponentWithType - -```javascript -ReactComponent findRenderedComponentWithType( - ReactComponent tree, function componentClass -) -``` - -`scryRenderedComponentsWithType()`와 비슷하지만 하나의 결과만 기대될 때 사용합니다. 하나의 결과를 리턴하거나 한개 이상의 결과가 나온 경우에는 예외를 던집니다. - -## 얕은 렌더링 - -얕은 렌더링은 "한 단계 깊이의" 컴포넌트를 렌더할 수 있는 실험적인 기능입니다. 자식 컴포넌트가 인스턴스화 되거나 렌더되는 등의 동작에 대한 걱정 없이 렌더 메소드가 반환하는 것만 검증합니다. 이 기능은 DOM이 필요하지 않습니다. - -```javascript -ReactShallowRenderer createRenderer() -``` - -테스트에서 얕은 렌더러를 생성하고자 할때 호출합니다. 이를 이벤트와 업데이트에 스스로 반응하는 컴포넌트를 렌더하기 위한 "장소"라고 생각할 수 있습니다. - -```javascript -shallowRenderer.render( - ReactElement element -) -``` - -`ReactDOM.render`와 유사합니다. - -```javascript -ReactElement shallowRenderer.getRenderOutput() -``` - -`render`가 호출 된 후, 얕게 렌더된 결과물을 반환합니다. 그 후엔 결과물에 대한 검증을 시작할 수 있습니다. 예를 들어 컴포넌트의 렌더 메소드가 다음을 반환한다면: - -```javascript -
                    - Title - -
                    -``` - -그 후에는 검증할 수 있습니다: - -```javascript -result = renderer.getRenderOutput(); -expect(result.type).toBe('div'); -expect(result.props.children).toEqual([ - Title, - -]); -``` - -현재 얕은 테스트는 refs를 지원하지 않는 등 몇가지 제약사항이 있습니다. 우리는 이 기능을 빠르게 먼저 배포하고 React 커뮤니티의 피드백을 받아 나아갈 방향을 찾고자 합니다. diff --git a/docs/docs/10.4-test-utils.md b/docs/docs/10.4-test-utils.md deleted file mode 100644 index b4aa8829e8..0000000000 --- a/docs/docs/10.4-test-utils.md +++ /dev/null @@ -1,250 +0,0 @@ ---- -id: test-utils -title: Test Utilities -permalink: docs/test-utils.html -prev: two-way-binding-helpers.html -next: clone-with-props.html ---- - -`ReactTestUtils` makes it easy to test React components in the testing framework of your choice. At Facebook we use [Jest](https://facebook.github.io/jest/) for painless JavaScript testing. Learn how to get started with Jest through the Jest website's [React Tutorial](http://facebook.github.io/jest/docs/tutorial-react.html#content). - -``` -var ReactTestUtils = require('react-addons-test-utils'); -``` - -> Note: -> -> Airbnb has released a testing utility called Enzyme, which makes it easy to assert, manipulate, and traverse your React Components' output. If you're deciding on a unit testing utility to use together with Jest, or any other test runner, it's worth checking out: [http://airbnb.io/enzyme/](http://airbnb.io/enzyme/) - -### Simulate - -```javascript -Simulate.{eventName}( - DOMElement element, - [object eventData] -) -``` - -Simulate an event dispatch on a DOM node with optional `eventData` event data. **This is possibly the single most useful utility in `ReactTestUtils`.** - -**Clicking an element** - -```javascript -// -var node = this.refs.button; -ReactTestUtils.Simulate.click(node); -``` - -**Changing the value of an input field and then pressing ENTER.** - -```javascript -// -var node = this.refs.input; -node.value = 'giraffe'; -ReactTestUtils.Simulate.change(node); -ReactTestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13}); -``` - -*Note that you will have to provide any event property that you're using in your component (e.g. keyCode, which, etc...) as React is not creating any of these for you.* - -`Simulate` has a method for [every event that React understands](/react/docs/events.html#supported-events). - -### renderIntoDocument - -```javascript -ReactComponent renderIntoDocument( - ReactElement instance -) -``` - -Render a component into a detached DOM node in the document. **This function requires a DOM.** - -> Note: -> -> You will need to have `window`, `window.document` and `window.document.createElement` - globally available **before** you import React. Otherwise React will think it can't access the DOM and methods like `setState` won't work. - -### mockComponent - -```javascript -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 `
                    ` (or other tag if `mockTagName` is provided) containing any provided children. - -### isElement - -```javascript -boolean isElement( - ReactElement element -) -``` - -Returns `true` if `element` is any ReactElement. - -### isElementOfType - -```javascript -boolean isElementOfType( - ReactElement element, - function componentClass -) -``` - -Returns `true` if `element` is a ReactElement whose type is of a React `componentClass`. - -### isDOMComponent - -```javascript -boolean isDOMComponent( - ReactComponent instance -) -``` - -Returns `true` if `instance` is a DOM component (such as a `
                    ` or ``). - -### isCompositeComponent - -```javascript -boolean isCompositeComponent( - ReactComponent instance -) -``` - -Returns `true` if `instance` is a composite component (created with `React.createClass()`). - -### isCompositeComponentWithType - -```javascript -boolean isCompositeComponentWithType( - ReactComponent instance, - function componentClass -) -``` - -Returns `true` if `instance` is a composite component (created with `React.createClass()`) whose type is of a React `componentClass`. - -### findAllInRenderedTree - -```javascript -array findAllInRenderedTree( - ReactComponent tree, - function test -) -``` - -Traverse all components in `tree` and accumulate all components where `test(component)` is `true`. This is not that useful on its own, but it's used as a primitive for other test utils. - -### scryRenderedDOMComponentsWithClass - -```javascript -array scryRenderedDOMComponentsWithClass( - ReactComponent tree, - string className -) -``` - -Finds all DOM elements of components in the rendered tree that are DOM components with the class name matching `className`. - -### findRenderedDOMComponentWithClass - -```javascript -DOMElement findRenderedDOMComponentWithClass( - ReactComponent tree, - string className -) -``` - -Like `scryRenderedDOMComponentsWithClass()` but expects there to be one result, and returns that one result, or throws exception if there is any other number of matches besides one. - -### scryRenderedDOMComponentsWithTag - -```javascript -array scryRenderedDOMComponentsWithTag( - ReactComponent tree, - string tagName -) -``` - -Finds all DOM elements of components in the rendered tree that are DOM components with the tag name matching `tagName`. - -### findRenderedDOMComponentWithTag - -```javascript -DOMElement findRenderedDOMComponentWithTag( - ReactComponent tree, - string tagName -) -``` - -Like `scryRenderedDOMComponentsWithTag()` but expects there to be one result, and returns that one result, or throws exception if there is any other number of matches besides one. - -### scryRenderedComponentsWithType - -```javascript -array scryRenderedComponentsWithType( - ReactComponent tree, - function componentClass -) -``` - -Finds all instances of components with type equal to `componentClass`. - -### findRenderedComponentWithType - -```javascript -ReactComponent findRenderedComponentWithType( - ReactComponent tree, - function componentClass -) -``` - -Same as `scryRenderedComponentsWithType()` but expects there to be one result and returns that one result, or throws exception if there is any other number of matches besides one. - -## Shallow rendering - -Shallow rendering is an experimental feature that lets you render a component "one level deep" and assert facts about what its render method returns, without worrying about the behavior of child components, which are not instantiated or rendered. This does not require a DOM. - -```javascript -ReactShallowRenderer createRenderer() -``` - -Call this in your tests to create a shallow renderer. You can think of this as a "place" to render the component you're testing, where it can respond to events and update itself. - -```javascript -shallowRenderer.render( - ReactElement element -) -``` - -Similar to `ReactDOM.render`. - -```javascript -ReactElement shallowRenderer.getRenderOutput() -``` - -After `render` has been called, returns shallowly rendered output. You can then begin to assert facts about the output. For example, if your component's render method returns: - -```javascript -
                    - Title - -
                    -``` - -Then you can assert: - -```javascript -var renderer = ReactTestUtils.createRenderer(); -result = renderer.getRenderOutput(); -expect(result.type).toBe('div'); -expect(result.props.children).toEqual([ - Title, - -]); -``` - -Shallow testing currently has some limitations, namely not supporting refs. We're releasing this feature early and would appreciate the React community's feedback on how it should evolve. diff --git a/docs/docs/10.4-test-utils.zh-CN.md b/docs/docs/10.4-test-utils.zh-CN.md deleted file mode 100644 index 3666672fa7..0000000000 --- a/docs/docs/10.4-test-utils.zh-CN.md +++ /dev/null @@ -1,244 +0,0 @@ ---- -id: test-utils-zh-CN -title: 测试工具 -permalink: docs/test-utils-zh-CN.html -prev: two-way-binding-helpers-zh-CN.html -next: clone-with-props-zh-CN.html ---- - -`ReactTestUtils` 使你在你选择的测试框架中 (我们使用 [Jest](https://facebook.github.io/jest/)) 测试 React 组件变得容易。 - -``` -var ReactTestUtils = require('react-addons-test-utils'); -``` - -### Simulate - -```javascript -Simulate.{eventName}( - DOMElement element, - [object eventData] -) -``` - -模拟一个在 DOM 节点上带有可选 `eventData` 事件数据的事件派遣(event dispatch)。**这可能是 `ReactTestUtils` 里单独最有用的工具。** - -**点击一个元素** - -```javascript -// -var node = this.refs.button; -ReactTestUtils.Simulate.click(node); -``` - -**改变 input 域的值然后点击 回车。** - -```javascript -// -var node = this.refs.input; -node.value = 'giraffe'; -ReactTestUtils.Simulate.change(node); -ReactTestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13}); -``` - -*注意你将必须提供任何你在你的组件里使用的事件属性(例如 keyCode, which, 等等)因为React没有为你创建任何这类东西。* - -`Simulate` has a method for [every event that React understands](/react/docs/events.html#supported-events). - -### renderIntoDocument - -```javascript -ReactComponent renderIntoDocument( - ReactElement instance -) -``` - -渲染一个组件到 document 里的 detached DOM 节点。**这个函数需要一个 DOM。** - -> 注意: -> -> 在你 import React **之前**,你需要让 `window`, `window.document` 和 `window.document.createElement` 全局可用。 -不然 React 会认为它不能访问 DOM 然后类似 `setState` 的方法会不工作。 - -### mockComponent - -```javascript -object mockComponent( - function componentClass, - [string mockTagName] -) -``` - -传入一个 mocked 组件模块到这个方法来给它增加有用的方法,使它可以被用作 dummy React 组件。代替像通常一样的渲染,组件会成为一个简单的包含了任意被提供的子级的 `
                    ` (或者其他 tag 名,如果提供了 `mockTagName`) - -### isElement - -```javascript -boolean isElement( - ReactElement element -) -``` - -返回 `true` 如果 `element` 是任意的 ReactElement。 - -### isElementOfType - -```javascript -boolean isElementOfType( - ReactElement element, - function componentClass -) -``` - -返回 `true` 如果 `element` 是一个类型是 React `componentClass` 的 ReactElement。 - -### isDOMComponent - -```javascript -boolean isDOMComponent( - ReactComponent instance -) -``` - -返回 `true` 如果 `instance` 是一个 DOM 组件 (比如一个 `
                    ` 或者 ``)。 - -### isCompositeComponent - -```javascript -boolean isCompositeComponent( - ReactComponent instance -) -``` - -返回 `true` 如果 `instance` 是一个复合组件 (由 `React.createClass()` 创建)。 - -### isCompositeComponentWithType - -```javascript -boolean isCompositeComponentWithType( - ReactComponent instance, - function componentClass -) -``` - -返回 `true` 如果 `instance` 是一个类型为 React `componentClass` 的复合组件 (由 `React.createClass()` 创建)。 - -### findAllInRenderedTree - -```javascript -array findAllInRenderedTree( - ReactComponent tree, - function test -) -``` - -遍历 `tree` 里所有的组件,并累积所有 `test(component)` 为 `true` 的组件。它本身并没有什么用,但是它被用作其他测试工具的基本元素。 - -### scryRenderedDOMComponentsWithClass - -```javascript -array scryRenderedDOMComponentsWithClass( - ReactComponent tree, string className -) -``` - -在渲染的树中查找所有 DOM组件的类名匹配`className` 的组件实例。 - -### findRenderedDOMComponentWithClass - -```javascript -ReactComponent findRenderedDOMComponentWithClass( - ReactComponent tree, - string className -) -``` - -类似 `scryRenderedDOMComponentsWithClass()` 除了只有一个返回结果,并且要么返回这个结果,要么如果还有其他的匹配项就抛出一个异常。 - -### scryRenderedDOMComponentsWithTag - -```javascript -array scryRenderedDOMComponentsWithTag( - ReactComponent tree, - string tagName -) -``` - -在渲染的树中查找所有 DOM 组件的 tag 名匹配 `tagName` 的组件实例。 - -### findRenderedDOMComponentWithTag - -```javascript -ReactComponent findRenderedDOMComponentWithTag( - ReactComponent tree, - string tagName -) -``` - -类似 `scryRenderedDOMComponentsWithTag()` 除了只有一个返回结果,并且要么返回这个结果,要么如果还有其他的匹配项就抛出一个异常。 - -### scryRenderedComponentsWithType - -```javascript -array scryRenderedComponentsWithType( - ReactComponent tree, - function componentClass -) -``` - -查找所有类型等于 `componentClass` 的组件实例。 - -### findRenderedComponentWithType - -```javascript -ReactComponent findRenderedComponentWithType( - ReactComponent tree, function componentClass -) -``` - -类似 `scryRenderedComponentsWithType()` 除了只有一个返回结果,并且要么返回这个结果,要么如果还有其他的匹配项就抛出一个异常。 - -## Shallow rendering(浅渲染) - -浅渲染是一个实验性特性,让你渲染一个组件为 "one level deep" 并且断言渲染方法返回的内容,不用担心子组件的行为,它们没有被实例化或者渲染。这个方式不需要一个 DOM。 - -```javascript -ReactShallowRenderer createRenderer() -``` - -在你的测试里调用它来创建一个浅渲染器。你可以把它想做是一个你渲染你要测试的组件的 "地方",它可以自己响应事件并更新。 - -```javascript -shallowRenderer.render( - ReactElement element -) -``` - -类似于 `ReactDOM.render`。 - -```javascript -ReactElement shallowRenderer.getRenderOutput() -``` - -在 `render` 被调用后,返回一个浅渲染的输出。你可以接着断言输出的内容。例如,如果你的组件的渲染方法返回: - -```javascript -
                    - Title - -
                    -``` - -然后你可以断言: - -```javascript -var renderer = ReactTestUtils.createRenderer(); -result = renderer.getRenderOutput(); -expect(result.type).toBe('div'); -expect(result.props.children).toEqual([ - Title, - -]); -``` - -浅测试现在有一些限制,即不支持 refs。我们在早期发布这个特性,并感激 React 社区关于它应该如何演化的反馈。 diff --git a/docs/docs/10.5-clone-with-props.it-IT.md b/docs/docs/10.5-clone-with-props.it-IT.md deleted file mode 100644 index ee690b9a51..0000000000 --- a/docs/docs/10.5-clone-with-props.it-IT.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -id: clone-with-props-it-IT -title: Clonare ReactElements -permalink: docs/clone-with-props-it-IT.html -prev: test-utils-it-IT.html -next: create-fragment-it-IT.html ---- - -> Nota: -> `cloneWithProps` è deprecato. Usa [React.cloneElement](top-level-api.html#react.cloneelement) al suo posto. - -In rare condizioni, potresti voler creare una copia di un elemento React con proprietà diverse da quelle dell'elemento originale. Un esempio è clonare gli elementi passati come `this.props.children` ed effettuarne il rendering con proprietà diverse: - -```js -var _makeBlue = function(element) { - return React.addons.cloneWithProps(element, {style: {color: 'blue'}}); -}; - -var Blue = React.createClass({ - render: function() { - var blueChildren = React.Children.map(this.props.children, _makeBlue); - return
                    {blueChildren}
                    ; - } -}); - -ReactDOM.render( - -

                    Questo testo è blu.

                    -
                    , - document.getElementById('container') -); -``` - -`cloneWithProps` non trasferisce gli attributi `key` o `ref` agli elementi clonati. Le proprietà `className` e `style` sono automaticamente riunite. diff --git a/docs/docs/10.5-clone-with-props.ja-JP.md b/docs/docs/10.5-clone-with-props.ja-JP.md deleted file mode 100644 index 3f71593254..0000000000 --- a/docs/docs/10.5-clone-with-props.ja-JP.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -id: clone-with-props -title: ReactElementsをクローンすること -permalink: docs/clone-with-props-ja-JP.html -prev: test-utils-ja-JP.html -next: create-fragment-ja-JP.html ---- - -> 注意: -> `cloneWithProps` は使用不可になりました。[React.cloneElement](top-level-api-ja-JP.html#react.cloneelement)を代わりに使用してください。 - -元のReact要素とは異なるプロパティを持った要素のコピーを作成したいと考える稀なケースがあるかと思います。1つの例としては、以下のように、 `this.props.children` に渡すように要素をクローンし、異なるプロパティを持つようそれらをレンダリングするものです。 - -```js -var _makeBlue = function(element) { - return React.addons.cloneWithProps(element, {style: {color: 'blue'}}); -}; - -var Blue = React.createClass({ - render: function() { - var blueChildren = React.Children.map(this.props.children, _makeBlue); - return
                    {blueChildren}
                    ; - } -}); - -ReactDOM.render( - -

                    This text is blue.

                    -
                    , - document.getElementById('container') -); -``` - -`cloneWithProps` は `key` や `ref` をクローンされた要素に渡すことはありません。 `className` や `style` は自動的にマージされます。 diff --git a/docs/docs/10.5-clone-with-props.ko-KR.md b/docs/docs/10.5-clone-with-props.ko-KR.md deleted file mode 100644 index c909ad73d1..0000000000 --- a/docs/docs/10.5-clone-with-props.ko-KR.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: clone-with-props-ko-KR -title: ReactElement 클론하기 -permalink: docs/clone-with-props-ko-KR.html -prev: test-utils-ko-KR.html -next: create-fragment-ko-KR.html ---- - -> 주의: -> `cloneWithProps`는 비추천입니다. 대신 [React.cloneElement](top-level-api.html#react.cloneelement)를 사용하세요. - -드문 경우긴 하지만 원래 엘리먼트와 다른 prop을 가진 React 엘리먼트의 복사본을 만들고 싶을 때가 있습니다. 예를 들면 `this.props.children`에 클론한 엘리먼트를 넘기고 다른 prop으로 렌더링하는 경우 입니다. - -```js -var cloneWithProps = require('react-addons-clone-with-props'); - -var _makeBlue = function(element) { - return cloneWithProps(element, {style: {color: 'blue'}}); -}; - -var Blue = React.createClass({ - render: function() { - var blueChildren = React.Children.map(this.props.children, _makeBlue); - return
                    {blueChildren}
                    ; - } -}); - -ReactDOM.render( - -

                    This text is blue.

                    -
                    , - document.getElementById('container') -); -``` - -`cloneWithProps`는 `key`나 `ref`를 클론된 엘리먼트에 전달하지 않습니다. `className`, `style` prop은 자동으로 머지됩니다. diff --git a/docs/docs/10.5-clone-with-props.md b/docs/docs/10.5-clone-with-props.md deleted file mode 100644 index dc1c14a320..0000000000 --- a/docs/docs/10.5-clone-with-props.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: clone-with-props -title: Cloning ReactElements -permalink: docs/clone-with-props.html -prev: test-utils.html -next: create-fragment.html ---- - -> Note: -> `cloneWithProps` is deprecated. Use [React.cloneElement](top-level-api.html#react.cloneelement) instead. - -In rare situations, you may want to create a copy of a React element with different props from those of the original element. One example is cloning the elements passed into `this.props.children` and rendering them with different props: - -```js -var cloneWithProps = require('react-addons-clone-with-props'); - -var _makeBlue = function(element) { - return cloneWithProps(element, {style: {color: 'blue'}}); -}; - -var Blue = React.createClass({ - render: function() { - var blueChildren = React.Children.map(this.props.children, _makeBlue); - return
                    {blueChildren}
                    ; - } -}); - -ReactDOM.render( - -

                    This text is blue.

                    -
                    , - document.getElementById('container') -); -``` - -`cloneWithProps` does not transfer `key` or `ref` to the cloned element. `className` and `style` props are automatically merged. diff --git a/docs/docs/10.5-clone-with-props.zh-CN.md b/docs/docs/10.5-clone-with-props.zh-CN.md deleted file mode 100644 index 5d2bf2002c..0000000000 --- a/docs/docs/10.5-clone-with-props.zh-CN.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: clone-with-props-zh-CN -title: 克隆 ReactElements -permalink: docs/clone-with-props-zh-CN.html -prev: test-utils-zh-CN.html -next: create-fragment-zh-CN.html ---- - -> 注意: -> `cloneWithProps` 被弃用了. 用 [React.cloneElement](top-level-api.html#react.cloneelement) 代替. - -在很罕见的情况下,你可能需要创建一个 React 元素的拷贝,它与初始的元素有不同的 props。一个例子是克隆这些传递到 `this.props.children` 的元素并用不同的 props 渲染他们。 - -```js -var cloneWithProps = require('react-addons-clone-with-props'); - -var _makeBlue = function(element) { - return cloneWithProps(element, {style: {color: 'blue'}}); -}; - -var Blue = React.createClass({ - render: function() { - var blueChildren = React.Children.map(this.props.children, _makeBlue); - return
                    {blueChildren}
                    ; - } -}); - -ReactDOM.render( - -

                    This text is blue.

                    -
                    , - document.getElementById('container') -); -``` - -`cloneWithProps` 不传递 `key` 或者 `ref` 到被克隆的元素。`className` 和 `style` props 被自动合并。 diff --git a/docs/docs/10.6-create-fragment.it-IT.md b/docs/docs/10.6-create-fragment.it-IT.md deleted file mode 100644 index 2325eb4e9b..0000000000 --- a/docs/docs/10.6-create-fragment.it-IT.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -id: create-fragment-it-IT -title: Frammenti con Chiave -permalink: docs/create-fragment-it-IT.html -prev: clone-with-props-it-IT.html -next: update-it-IT.html ---- - -In molti casi, puoi utilizzare la proprietà `key` per specificare chiavi sugli elementi che restituisci da `render`. Tuttavia, questo approccio fallisce in una situazione: se hai due insiemi di figli che devi riordinare, non esiste alcun modo di assegnare una chiave a ciascuno di essi senza aggiungere un elemento contenitore. - -Ovvero, se hai un componente come il seguente: - -```js -var Swapper = React.createClass({ - propTypes: { - // `leftChildren` e `rightChildren` possono essere una stringa, un elemento, un array, etc. - leftChildren: React.PropTypes.node, - rightChildren: React.PropTypes.node, - - swapped: React.PropTypes.bool - } - render: function() { - var children; - if (this.props.swapped) { - children = [this.props.rightChildren, this.props.leftChildren]; - } else { - children = [this.props.leftChildren, this.props.rightChildren]; - } - return
                    {children}
                    ; - } -}); -``` - -I figli saranno smontati e rimontati nel momento in cui cambi la proprietà `swapped` poiché non ci sono chiavi che marcano i due insiemi di figli. - -Per risolvere questo problema, puoi utilizzare `React.addons.createFragment` per dare una chiave a ciascun insieme di figli. - -#### `ReactFragment React.addons.createFragment(object children)` - -Anziché creare array, scriviamo: - -```js -if (this.props.swapped) { - children = React.addons.createFragment({ - right: this.props.rightChildren, - left: this.props.leftChildren - }); -} else { - children = React.addons.createFragment({ - left: this.props.leftChildren, - right: this.props.rightChildren - }); -} -``` - -Le chiavi degli oggetti passati (ovvero, `left` e `right`) sono usate come chiavi per l'intero insieme di figli, e l'ordine delle chiavi dell'oggetto è utilizzato per determinare l'ordine dei figli visualizzati. Con questo cambiamento, i due insiemi di figli saranno correttamente riordinati nel DOM senza bisogno di smontaggio. - -Il valore di ritorno di `createFragment` deve essere trattato come un oggetto opaco; puoi usare gli helper `React.Children` per iterare su un frammento ma non dovresti accedervi direttamente. Nota anche che ci stiamo affidando al motore JavaScript per preservare l'ordine dell'enumerazione degli oggetti, che non viene garantito dalla specifica ma è implementato dai principali browser e macchine virtuali per oggetti con chiavi non numeriche. - -> **Nota:** -> -> In un futuro, `createFragment` potrebbe essere sostituito da una API quale -> -> ```js -> return ( ->
                    -> {this.props.rightChildren}, -> {this.props.leftChildren} ->
                    -> ); -> ``` -> -> che ti permette di assegnare chiavi direttamente in JSX senza aggiungere elementi contenitore. diff --git a/docs/docs/10.6-create-fragment.ja-JP.md b/docs/docs/10.6-create-fragment.ja-JP.md deleted file mode 100644 index 3de2fce776..0000000000 --- a/docs/docs/10.6-create-fragment.ja-JP.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -id: create-fragment -title: キー付けされたフラグメント -permalink: docs/create-fragment-ja-JP.html -prev: clone-with-props-ja-JP.html -next: update-ja-JP.html ---- - -多くの場合、 `render` から返された要素のキーを特定するために、 `key` プロパティを使用します。しかし、以下のような特定の状況では、こういったことを行うことはできません。何度も並び替える必要のある2つの子要素を持っているときには、ラッパーの要素を加える以外にそれぞれのセットのキーを追加する方法はありません。 - -これは、以下のようなコンポーネントがある場合には、 - -```js -var Swapper = React.createClass({ - propTypes: { - // `leftChildren` と `rightChildren` は文字列や、要素や、配列などになり得ます。 - leftChildren: React.PropTypes.node, - rightChildren: React.PropTypes.node, - - swapped: React.PropTypes.bool - } - render: function() { - var children; - if (this.props.swapped) { - children = [this.props.rightChildren, this.props.leftChildren]; - } else { - children = [this.props.leftChildren, this.props.rightChildren]; - } - return
                    {children}
                    ; - } -}); -``` - -2つの子要素のセットを表すキーがないため、 `swapped` プロパティを変更するたびに子要素はアンマウントされ、再度マウントされます。 - -この問題を解決するために、子要素のセットのキーを与える `React.addons.createFragment` を使用することができます。 - -#### `ReactFragment React.addons.createFragment(object children)` - -配列を作成する代わりに、以下のように記述することができます。 - -```js -if (this.props.swapped) { - children = React.addons.createFragment({ - right: this.props.rightChildren, - left: this.props.leftChildren - }); -} else { - children = React.addons.createFragment({ - left: this.props.leftChildren, - right: this.props.rightChildren - }); -} -``` - -渡されたオブジェクトのキー(`left` や `right` のことです)は子要素のセット全体のキーとして使用され、そのオブジェクトのキーの順序はレンダリングされた子要素の順序を決める際に使用されます。この変更により、2つの子要素のセットはアンマウントされることなく、DOMの中で適切に順序立てられます。 - -`createFragment` の戻り値は、不透明なオブジェクトとして扱われるべきです。つまり、 `React.Children` ヘルパーを、フラグメントのなかでループするために使用することはできますが、直接アクセスするべきではないということです。私たちはいまオブジェクトの一覧における順序を保存するのにJavaScriptのエンジンに頼っていることに注意してください。それは、仕様が保証されているわけではありませんが、数に関するものではないキーとオブジェクトは全てのメジャーなブラウザやVMで実行されます。 - -> **注意:** -> 将来、 `createFragment` は以下のようなAPIに変わるでしょう。 -> -> ```js -> return ( ->
                    -> {this.props.rightChildren}, -> {this.props.leftChildren} ->
                    -> ); -> ``` -> -> ラッパーの要素を加えることなく、JSXの中に直接キーをアサインすることができます。 diff --git a/docs/docs/10.6-create-fragment.ko-KR.md b/docs/docs/10.6-create-fragment.ko-KR.md deleted file mode 100644 index 6e4d2a1774..0000000000 --- a/docs/docs/10.6-create-fragment.ko-KR.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -id: create-fragment-ko-KR -title: 키가 할당된 프래그먼트 -permalink: docs/create-fragment-ko-KR.html -prev: clone-with-props-ko-KR.html -next: update-ko-KR.html ---- - -대부분의 경우는 `key` prop으로 `render`에서 반환된 엘리먼트에 키를 명시할 수 있습니다. 하지만 말썽을 부리는 경우가 한가지 있습니다: 재정렬을 할 두개의 자식 집합을 가지고 있는 경우, 감싸는 엘리먼트 없이 각각의 집합에 키를 부여하는 것은 불가능 합니다. - -이 말은, 만약 다음과 같은 컴포넌트가 있다면: - -```js -var Swapper = React.createClass({ - propTypes: { - // `leftChildren`과 `rightChildren`은 문자열, 엘리먼트, 배열 혹은 다른 무언가 일 수 있음. - leftChildren: React.PropTypes.node, - rightChildren: React.PropTypes.node, - - swapped: React.PropTypes.bool - }, - render: function() { - var children; - if (this.props.swapped) { - children = [this.props.rightChildren, this.props.leftChildren]; - } else { - children = [this.props.leftChildren, this.props.rightChildren]; - } - return
                    {children}
                    ; - } -}); -``` - -`swapped` prop을 변경할 경우 자식은 마운트 해제되거나 다시 마운트 될 수 있습니다. 두 자식 집합에 키가 할당되지 않았기 때문입니다. - -이 문제를 해결하기 위해서 `createFragment`를 사용해 자식 집합에 키를 부여할 수 있습니다. - -#### `Array createFragment(object children)` - -배열을 만드는 대신에 다음과 같이 해볼 수 있습니다: - -```js -var createFragment = require('react-addons-create-fragment'); - -if (this.props.swapped) { - children = createFragment({ - right: this.props.rightChildren, - left: this.props.leftChildren - }); -} else { - children = createFragment({ - left: this.props.leftChildren, - right: this.props.rightChildren - }); -} -``` - -전달된 객체의 키(`left`, `right`)는 모든 자식 집합의 키로 사용됩니다. 그리고 객체에서 키들의 순서는 렌더된 자식들의 순서를 결정하는데 사용됩니다. 이러한 변경으로 두 자식 집합은 언마운팅하지 않고도 DOM에서 적절하게 재정렬 됩니다. - -`createFragment`의 반환값은 불명확한 객체로 취급되어야 합니다; `React.Children` 헬퍼를 사용해 프래그먼트를 순환할 수 있지만 직접 접근해서는 안됩니다. 명세에는 없지만 모든 주요 브라우저와 VM들에서 JavaScript 엔진이 숫자가 아닌 키에 대해서도 객체 목록 순서를 보존한다는 점을 주의하세요. - -> **주의:** -> -> 미래에 `createFragment`는 대략 다음과 같은 API로 교체될 것입니다 -> -> ```js -> return ( ->
                    -> {this.props.rightChildren}, -> {this.props.leftChildren} ->
                    -> ); -> ``` -> -> JSX에서 엘리먼트로 감싸지 않고도 key를 바로 선언할 수 있게 될 것입니다. diff --git a/docs/docs/10.6-create-fragment.zh-CN.md b/docs/docs/10.6-create-fragment.zh-CN.md deleted file mode 100644 index 620bba48c0..0000000000 --- a/docs/docs/10.6-create-fragment.zh-CN.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -id: create-fragment-zh-CN -title: Keyed Fragments -permalink: docs/create-fragment-zh-CN.html -prev: clone-with-props-zh-CN.html -next: update-zh-CN.html ---- - -在大多数情况下,你可以使用 `key` prop 指定你从 `render` 返回的元素的 keys。然而,这在一个情况下会失败:如果你有两组你需要记录的子级,将没有办法在不使用包裹元素的情况下放置一个 key 到每组上。 - -即是,如果你有一个像这样的组件: - -```js -var Swapper = React.createClass({ - propTypes: { - // `leftChildren` and `rightChildren` can be a string, element, array, etc. - leftChildren: React.PropTypes.node, - rightChildren: React.PropTypes.node, - - swapped: React.PropTypes.bool - }, - render: function() { - var children; - if (this.props.swapped) { - children = [this.props.rightChildren, this.props.leftChildren]; - } else { - children = [this.props.leftChildren, this.props.rightChildren]; - } - return
                    {children}
                    ; - } -}); -``` - -这些子级会在当你改变 `swapped` prop 时加载和卸载,因为没有任何的 key 标记在这两组子级上。 - -要解决这个问题,你可以使用 `createFragment` 插件来给予这两组子级 keys. - -#### `Array createFragment(object children)` - -代替创建数组,我们这样写: - -```js -var createFragment = require('react-addons-create-fragment'); - -if (this.props.swapped) { - children = createFragment({ - right: this.props.rightChildren, - left: this.props.leftChildren - }); -} else { - children = createFragment({ - left: this.props.leftChildren, - right: this.props.rightChildren - }); -} -``` - -被传入对象的 keys (即 `left` 和 `right`)被用作为整组子级的 keys,并且对象 keys 的顺序被用于决定渲染子级的顺序。通过这个改变,这两个子级将会恰当的在 DOM 里排序,而不被卸载。 - -`createFragment` 的返回值应该被对待为一个不透明的对象;你可以使用 `React.Children` 来遍历一个 fragment 但是不应该直接访问它。同样注意,我们依赖于 JavaScript 引擎保留了对象的枚举顺序,这点在 spec 上是不保证的,但是所有主要的浏览器和 VMs 都对非数字键的对象实现了这个特性。 - -> **注意:** -> -> 将来,`createFragment` 也许会被替换为如下的API: -> -> ```js -> return ( ->
                    -> {this.props.rightChildren}, -> {this.props.leftChildren} ->
                    -> ); -> ``` -> -> 允许你直接在 JSX 里赋值 keys 而不用添加包裹元素。 diff --git a/docs/docs/10.7-update.it-IT.md b/docs/docs/10.7-update.it-IT.md deleted file mode 100644 index 8cd3165b0d..0000000000 --- a/docs/docs/10.7-update.it-IT.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -id: update-it-IT -title: Helper per l'Immutabilità -permalink: docs/update-it-IT.html -prev: create-fragment-it-IT.html -next: pure-render-mixin-it-IT.html ---- - -React ti permette di usare qualunque stile per la gestione dei dati che desideri, incluso la mutazione. Tuttavia, se puoi usare dati immutabili in parti critiche per le prestazioni della tua applicazione è facile implementare rapidamente un metodo `shouldComponentUpdate()` che aumenta significativamente la velocità della tua applicazione. - -Avere a che fare con dati immutabili in JavaScript è più difficile che in linguaggi progettati a tale scopo, come [Clojure](http://clojure.org/). Tuttavia, abbiamo fornito un semplice helper per l'immutabilità, `update()`, che rende avere a che fare con questo tipo di dati molto più semplice, *senza* cambiare fondamentalmente la rappresentazione dei tuoi dati. Se puoi anche dare un'occhiata alla libreria [Immutable-js](https://facebook.github.io/immutable-js/docs/) di Facebook e la sezione [Prestazioni Avanzate](/react/docs/advanced-performance.html) per maggiori dettagli su Immutable-js. - -## L'idea fondamentale - -Se muti i tuoi dati nella seguente maniera: - -```js -myData.x.y.z = 7; -// oppure... -myData.a.b.push(9); -``` - -non hai modo di determinare quali dati siano cambiati dal momento che la copia precedente è stata sovrascritta. Invece, devi creare una nuova copia di `myData` e cambiare solo le parti che vanno cambiate. Allora puoi confrontare la vecchia copia di `myData` con la nuova in `shouldComponentUpdate()` usando l'operatore di uguaglianza stretta `===`: - -```js -var newData = deepCopy(myData); -newData.x.y.z = 7; -newData.a.b.push(9); -``` - -Sfortunatamente, le copie profonde sono costose, e a volte impossibili. Puoi alleviare questa limitazione copiando soltanto gli oggetti che devono essere cambiati e riutilizzando gli oggetti che nonsono cambiati. Sfortunatamente, nel JavaScript odierno questa può essere un'operazione difficoltosa: - -```js -var newData = extend(myData, { - x: extend(myData.x, { - y: extend(myData.x.y, {z: 7}), - }), - a: extend(myData.a, {b: myData.a.b.concat(9)}) -}); -``` - -Mentre questo codice ha prestazioni accettabili (dal momento che effettua soltanto una copia superficiale di `log n` oggetti e riutilizza i rimanenti), è una gran scocciatura da scrivere. Guarda quanta ripetizione! Questo non è soltanto fastidioso, ma offre una grande superficie di attacco per i bachi. - -`update()` fornisce un semplice zucchero sintattico attorno a questo pattern per rendere più semplice la scrittura di questo codice. Questo codice diventa: - -```js -var newData = React.addons.update(myData, { - x: {y: {z: {$set: 7}}}, - a: {b: {$push: [9]}} -}); -``` - -Mentre la sintassi richiede qualche tempo per abituarsi (anche se è ispirata dal [linguaggio di query di MongoDB](http://docs.mongodb.org/manual/core/crud-introduction/#query)) non c'è ridondanza, può essere analizzato staticamente e non richiede la scrittura di più codice della versione mutativa. - -Le chiavi con il prefisso `$` sono chiamate *comandi*. La struttura dati che stanno "mutando" viene chiamata *bersaglio*. - -## Comandi disponibili - - * `{$push: array}` invoca `push()` sul bersagio passando ciascun elemento di `array`. - * `{$unshift: array}` invoca `unshift()` sul bersagio passando ciascun elemento di `array`. - * `{$splice: array of arrays}` per ogni elemento di `arrays` invoca `splice()` sul bersaglio con i parametri forniti dall'elemento. - * `{$set: any}` sostituisce l'intero bersaglio. - * `{$merge: object}` unisce le chiavi di `object` con il bersaglio. - * `{$apply: function}` passa il valore attuale alla funzione e lo aggiorna con il nuovo valore da essa restituito. - -## Esempi - -### Semplice inserimento in coda - -```js -var initialArray = [1, 2, 3]; -var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4] -``` -`initialArray` is still `[1, 2, 3]`. - -### Collezioni annidate - -```js -var collection = [1, 2, {a: [12, 17, 15]}]; -var newCollection = update(collection, {2: {a: {$splice: [[1, 1, 13, 14]]}}}); -// => [1, 2, {a: [12, 13, 14, 15]}] -``` -Questo accede all'indice `2` di `collection`, alla chiave `a`, ed effettua lo splice di un elemento a partire dall'indice `1` (per rimuovere `17`) e al contempo inserisce `13` e `14`. - -### Aggiornare un valore basandosi sul suo valore attuale - -```js -var obj = {a: 5, b: 3}; -var newObj = update(obj, {b: {$apply: function(x) {return x * 2;}}}); -// => {a: 5, b: 6} -// Questa è una forma equivalente, ma diventa prolissa per profonde collezioni annidate: -var newObj2 = update(obj, {b: {$set: obj.b * 2}}); -``` - -### Unione (superficiale) - -```js -var obj = {a: 5, b: 3}; -var newObj = update(obj, {$merge: {b: 6, c: 7}}); // => {a: 5, b: 6, c: 7} -``` diff --git a/docs/docs/10.7-update.ja-JP.md b/docs/docs/10.7-update.ja-JP.md deleted file mode 100644 index fb54233ae1..0000000000 --- a/docs/docs/10.7-update.ja-JP.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -id: update -title: 不変性のヘルパ -permalink: docs/update-ja-JP.html -prev: create-fragment-ja-JP.html -next: pure-render-mixin-ja-JP.html ---- - -Reactは変化を含む、使用したいデータマネジメントのスタイルであればどういったものであっても使用することができます。しかし、アプリケーションの、パフォーマンスが重要な部分において不変なデータを使用できる場合は、速い `shouldComponentUpdate()` メソッドを実行して、簡単にアプリケーションのスピードを著しく速くすることができます。 - -[Clojure](http://clojure.org/)のような、不変なデータの扱いのためにデザインされた言語よりも、JavaScriptでそれを行うことは難しいです。しかし、単純な不変性のヘルパである、 `update()` が提供されています。それは、データがどのように表されるかということを基本的には変更すること *なく* データのタイプを扱うことを簡単にします。Immutable-jsについての詳細は、Facebookの[Immutable-js](https://facebook.github.io/immutable-js/docs/#/)や[進歩したパフォーマンス](/react/docs/advanced-performance.html)をご覧ください。 - -## 主要な考え - -もし変更する予定のデータが以下のようなものであれば、 - -```js -myData.x.y.z = 7; -// または... -myData.a.b.push(9); -``` - -以前のコピーが上書きされるので、どのデータが変更されたか判断する方法はありません。代わりに、 `myData` の新しいコピーを作成する必要があり、変更される必要がある部分のみを変更します。それから、 `myData` の古いコピーと新しいコピーを `shouldComponentUpdate()` の中で以下のように、3つのイコールを使用して比較することができます。 - -```js -var newData = deepCopy(myData); -newData.x.y.z = 7; -newData.a.b.push(9); -``` - -不幸なことに、ディープコピーはコストがかかり、不可能なときもあります。変更される必要があるオブジェクトをコピーすることと、変更されていないオブジェクトを再利用することによってのみ、これを代替することができます。不幸なことに、今日のJavaScriptでは、こういったことは面倒です。 - -```js -var newData = extend(myData, { - x: extend(myData.x, { - y: extend(myData.x.y, {z: 7}), - }), - a: extend(myData.a, {b: myData.a.b.concat(9)}) -}); -``` - -動きが速い一方で( `log n` オブジェクトのシャローコピーを作成し、残りを再利用するため)、記述するのには多くのコストがかかります。全てのコードの繰り返しを見てください。それらはつまらないものではなく、多くのバグの表面を提供します。 - -`update()` はこのようなパターンにおいて、コードを簡単に記述するための単純な糖衣構文を提供します。そのコードは以下のようになります。 - -```js -var newData = React.addons.update(myData, { - x: {y: {z: {$set: 7}}}, - a: {b: {$push: [9]}} -}); -``` - -シンタックスは少し慣れが必要ですが([MongoDBのクエリ言語](http://docs.mongodb.org/manual/core/crud-introduction/#query)にインスパイアされているため)、冗長性はありません。静的に分析し、変更ができるバージョンと比べてタイプする量がすごく増えているわけではありません。 - -`$` から始まるキーは *コマンド* と呼ばれます。それらが「変更する」データ構造は *ターゲット* と呼ばれます。 - -## 使用できるコマンド - - * `{$push: array}` ターゲットに `array` の全ての要素を `push()` します。 - * `{$unshift: array}` ターゲットの `array` の全ての要素を `unshift()` します。 - * `{$splice: array of arrays}` `arrays` の全ての要素について、その要素によって提供されるパラメータのターゲットにおいて、 `splice()` を呼び出します。 - * `{$set: any}` ターゲットを完全に置き換えます。 - * `{$merge: object}` `object` のキーをターゲットとマージします。 - * `{$apply: function}` 現在の値を関数に渡し、返された新しい値によってそれを更新します。 - -## 例 - -### 単純なプッシュ - -```js -var initialArray = [1, 2, 3]; -var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4] -``` -`initialArray` は `[1, 2, 3]` のままです。 - -### ネストしたコレクション - -```js -var collection = [1, 2, {a: [12, 17, 15]}]; -var newCollection = update(collection, {2: {a: {$splice: [[1, 1, 13, 14]]}}}); -// => [1, 2, {a: [12, 13, 14, 15]}] -``` - -これは、 `collection` のインデックスが `2` である要素にアクセスし、インデックスが `1` である要素に( `17` を削除し)`13` と `14` を挿入することで繋ぎ合わせます。 - -### 現在の値に基づいて値を更新すること - -```js -var obj = {a: 5, b: 3}; -var newObj = update(obj, {b: {$apply: function(x) {return x * 2;}}}); -// => {a: 5, b: 6} -// 以下は上と同義ですが、ネストが深いコレクションにとっては冗長になります。 -var newObj2 = update(obj, {b: {$set: obj.b * 2}}); -``` - -### (シャロー)マージ - -```js -var obj = {a: 5, b: 3}; -var newObj = update(obj, {$merge: {b: 6, c: 7}}); // => {a: 5, b: 6, c: 7} -``` diff --git a/docs/docs/10.7-update.ko-KR.md b/docs/docs/10.7-update.ko-KR.md deleted file mode 100644 index fd32304b2f..0000000000 --- a/docs/docs/10.7-update.ko-KR.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -id: update-ko-KR -title: 불변성 헬퍼들 -permalink: docs/update-ko-KR.html -prev: create-fragment-ko-KR.html -next: pure-render-mixin-ko-KR.html ---- - -React에서는 mutation을 포함해 어떤 데이터 관리 방식도 사용하실 수 있습니다. 하지만 애플리케이션의 성능이 중요한 부분에서 불변의(immutable) 데이터를 사용할 수 있다면, 쉽게 빠른 `shouldComponentUpdate()` 메소드를 구현해 애플리케이션의 속도를 크게 향상시킬 수 있습니다. - -JavaScript에서 불변성의 데이터를 다루는 것은 [Clojure](http://clojure.org/)같이 그것을 위해 디자인된 언어로 다루는 것보다는 어렵습니다. 하지만, React는 간단한 불변성 헬퍼를 제공합니다. `update()`는 이런 종류의 데이터를 근본적인 변화 *없이* 쉽게 다루도록 해줍니다. Immutable-js에 관한 좀 더 자세한 정보는 페이스북의 [Immutable-js](https://facebook.github.io/immutable-js/docs/)나 [성능 심화](/react/docs/advanced-performance-ko-KR.html)을 참조하세요. - -## 주요 아이디어 - -만약 데이터를 이렇게 변화시킨다면: - -```js -myData.x.y.z = 7; -// or... -myData.a.b.push(9); -``` - -이전의 카피가 덮어씌워진다면 어떤 자료가 바뀌었는지 알 방도가 없습니다. 대신에, `myData`의 새로운 카피를 만들고 오직 변화가 필요한 부분만 바꿀 필요가 있습니다. 그 다음 `shouldComponentUpdate()` 에서 `myData`의 이전 카피와 새로운 카피를 `===` 연산자를 사용하여 비교할 수 있습니다. - -```js -var newData = deepCopy(myData); -newData.x.y.z = 7; -newData.a.b.push(9); -``` - -하지만 깊은 복사는 비싸고, 가끔은 불가능하기도 합니다. 변화가 필요한 객체만 복제하고, 변화가 없는 객체는 다시 사용하는 방법으로만 비용을 줄일 수 있습니다. 안타깝지만 오늘날의 JavaScript에서는 그 방법이 성가실 수 있습니다: - -```js -var newData = extend(myData, { - x: extend(myData.x, { - y: extend(myData.x.y, {z: 7}), - }), - a: extend(myData.a, {b: myData.a.b.concat(9)}) -}); -``` - -이것은 꽤 성능이 좋긴 하지만 (`log n`개의 객체만 얕은 복사하고, 나머지는 재사용하기 때문에), 일일히 쓰기엔 큰 고통이 따릅니다. 이 반복들을 보세요! 이건 짜증날 뿐만 아니라 버그들을 야기할수도 있습니다. - -`update()`는 이런 패턴 속에서 코드를 더 쉽게 쓸 수 있도록 편의 문법을 제공합니다. 코드는 이렇습니다: - -```js -var update = require('react-addons-update'); - -var newData = update(myData, { - x: {y: {z: {$set: 7}}}, - a: {b: {$push: [9]}} -}); -``` - -([MongoDB 쿼리 언어](http://docs.mongodb.org/manual/core/crud-introduction/#query)에서 영감을 받은) 이 문법에 익숙해지기에는 시간이 조금 걸리긴 하지만, 쓸모 없는 반복이 없고 정적분석이 가능할 뿐더러 변할 수 있는(mutative) 버전보다 더 많은 타이핑이 필요하지도 않습니다. - - -`$`가 앞에 붙어있는 키들은 *커맨드* 라고 불립니다. "변하는" 자료 구조는 *타겟* 이라고 불립니다. - -## 사용가능한 커맨드들 - - * `{$push: array}` 모든 아이템들을 타겟에 있는 `array`에 `push()`합니다. - * `{$unshift: array}` 타겟속 `array`에 있는 모든 아이템들을 `unshift()`합니다. - * `{$splice: array of arrays}` `arrays` 안의 각 아이템들이 `splice()`를 주어진 인자들을 사용해 호출하게 합니다. - * `{$set: any}` 타겟 전체를 대체합니다. - * `{$merge: object}` 타겟과 `object`의 키들을 병합합니다. - * `{$apply: function}` 는 지금 값을 함수에 전달하고 새로운 리턴 값으로 업데이트합니다. - -## 예제 - -### 간단한 push - -```js -var initialArray = [1, 2, 3]; -var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4] -``` -`initialArray` 은 여전히 `[1, 2, 3]` 입니다. - -### 중첩된 컬렉션 - -```js -var collection = [1, 2, {a: [12, 17, 15]}]; -var newCollection = update(collection, {2: {a: {$splice: [[1, 1, 13, 14]]}}}); -// => [1, 2, {a: [12, 13, 14, 15]}] -``` -이것은 `collection`의 인덱스 `2`의 키 `a`에 접근해, 인덱스 `1`에 있는 한 아이템을 접합(splice)해서(`17`를 제거하고) `13`, `14`를 추가합니다. - -### 현재 상태에 의거해 값을 업데이트 - -```js -var obj = {a: 5, b: 3}; -var newObj = update(obj, {b: {$apply: function(x) {return x * 2;}}}); -// => {a: 5, b: 6} -// 위의 것과 같은 동작을 합니다만, 깊게 중첩된 컬렉션들에서는 더 장황해 집니다. -var newObj2 = update(obj, {b: {$set: obj.b * 2}}); -``` - -### (얕은) 합병 - -```js -var obj = {a: 5, b: 3}; -var newObj = update(obj, {$merge: {b: 6, c: 7}}); // => {a: 5, b: 6, c: 7} -``` diff --git a/docs/docs/10.7-update.zh-CN.md b/docs/docs/10.7-update.zh-CN.md deleted file mode 100644 index 36fc29472c..0000000000 --- a/docs/docs/10.7-update.zh-CN.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -id: update-zh-CN -title: immutability 助手 -permalink: docs/update-zh-CN.html -prev: create-fragment-zh-CN.html -next: pure-render-mixin-zh-CN.html ---- - -React 让你可以使用任何你想要的数据管理方式,包括 mutation。然而,如果你可以在你的应用的性能关键性部分里使用 immutable 数据,将会易于实现一个快速的 `shouldComponentUpdate()` 方法来显著加速你的 app。 - -在 JavaScript 里处理 immutable 数据比在为此设计的语言中要难的多,比如 [Clojure](http://clojure.org/)。然而,我们提供了一个简单的 immutability 助手,`update()`,它使处理这类数据容易多了,*不用* 根本性的改变你的数据的表达方式。你也同样可以看一看 Facebook 的 [Immutable-js](https://facebook.github.io/immutable-js/docs/) 和[Advanced Performance](/react/docs/advanced-performance.html) 了解更多关于 Immutable-js 的信息。 - -## 主要的思路 - -如果你像这样变动数据: - -```js -myData.x.y.z = 7; -// or... -myData.a.b.push(9); -``` - -你将没有任何办法决定哪个数据被改变了,因为之前的拷贝已经被覆盖。作为替代,你需要创建一个新的 `myData` 的拷贝并且只修改需要改变的地方。然后你可以用三个等于在 `shouldComponentUpdate()` 里比较旧的 `myData` 拷贝与新的拷贝: - -```js -var newData = deepCopy(myData); -newData.x.y.z = 7; -newData.a.b.push(9); -``` - -不幸的是,深拷贝很昂贵,并且有时候不可能。你可以通过仅仅拷贝需要被改变和重用没有改变的对象来缓解这个情况。不幸的是,在当今的 JavaScript 里这会很笨重: - -```js -var newData = extend(myData, { - x: extend(myData.x, { - y: extend(myData.x.y, {z: 7}), - }), - a: extend(myData.a, {b: myData.a.b.concat(9)}) -}); -``` - -虽然这相当高性能(因为只对 `log n` 的对象进行了浅拷贝并重用了剩下的),但它写起来很痛苦。看看所有重复的代码!这不仅仅是烦人的,同时也提供了一大片 bugs 区域。 - -`update()` 提供了这个模式的简单语法糖来使写这类代码更容易。上面的代码变成: - -```js -var update = require('react-addons-update'); - -var newData = update(myData, { - x: {y: {z: {$set: 7}}}, - a: {b: {$push: [9]}} -}); -``` - -虽然这个语法需要花一些时间来适应(它的灵感来自于 [MongoDB's query language](http://docs.mongodb.org/manual/core/crud-introduction/#query)),但是没有冗余,它可静态分析并且没有 mutative 版本那么多键入。 - -`$`-前缀的 keys 被称为 *命令*。被 "变动的" 数据结构被称为 *目标*。 - -## 有效的命令 - - * `{$push: array}` 在目标上 `push()` 所有 `array` 里的项目。 - * `{$unshift: array}` 在目标上 `unshift()` 所有 `array` 里的项目。 - * `{$splice: array of arrays}` 在目标上对于每一个 `arrays` 里的项目使用项目提供的参数调用 `splice()`。 - * `{$set: any}` 整个替换目标. - * `{$merge: object}` 合并 目标和 `object` 的 keys. - * `{$apply: function}` 传递当前的值给 function 并用返回值更新它。 - -## 例子 - -### 简单的 push - -```js -var initialArray = [1, 2, 3]; -var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4] -``` -`initialArray` is still `[1, 2, 3]`. - -### 嵌套的 collections - -```js -var collection = [1, 2, {a: [12, 17, 15]}]; -var newCollection = update(collection, {2: {a: {$splice: [[1, 1, 13, 14]]}}}); -// => [1, 2, {a: [12, 13, 14, 15]}] -``` -本例访问了 `collection` 的`2`索引下的键`a`,并且拼接了一个从索引`1`开始(移除`17`)并插入`13`和`14`的项目。 - -### 基于当前的值更新新值 - -```js -var obj = {a: 5, b: 3}; -var newObj = update(obj, {b: {$apply: function(x) {return x * 2;}}}); -// => {a: 5, b: 6} -// This is equivalent, but gets verbose for deeply nested collections: -var newObj2 = update(obj, {b: {$set: obj.b * 2}}); -``` - -### (浅) 合并 - -```js -var obj = {a: 5, b: 3}; -var newObj = update(obj, {$merge: {b: 6, c: 7}}); // => {a: 5, b: 6, c: 7} -``` diff --git a/docs/docs/10.8-pure-render-mixin.it-IT.md b/docs/docs/10.8-pure-render-mixin.it-IT.md deleted file mode 100644 index 1dccb3b469..0000000000 --- a/docs/docs/10.8-pure-render-mixin.it-IT.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -id: pure-render-mixin-it-IT -title: PureRenderMixin -permalink: docs/pure-render-mixin-it-IT.html -prev: update-it-IT.html -next: perf-it-IT.html ---- - -Se la funzione render del tuo componente React è "pura" (in altre parole, visualizza lo stesso risultato a partire dagli stessi proprietà e stato), puoi usare questo mixin per un incremento di prestazioni in alcuni casi. - -Esempio: - -```js -var PureRenderMixin = require('react/addons').addons.PureRenderMixin; -React.createClass({ - mixins: [PureRenderMixin], - - render: function() { - return
                    foo
                    ; - } -}); -``` - -Dietro le quinte, il mixin implementa [shouldComponentUpdate](/react/docs/component-specs.html#updating-shouldcomponentupdate), nel quale confronta i valori attuali di `this.props` e `this.state` con i successivi e restituisce `false` se l'uguaglianza è verificata. - -> Nota: -> -> Questo confronto tra gli oggetti è soltanto superficiale. Se questi contengono strutture dati complesse, può causare dei falsi negativi per differenze in profondità. Effettua il mix in componenti la cui struttura di `this.props` e `this.state` sia semplice, oppure utilizza `forceUpdate()` quando si ha la certezza che le strutture dati siano cambiate in profondità. In alternativa, considera l'utilizzo di [oggetti immutabili](https://facebook.github.io/immutable-js/) per facilitare il confronto rapido di oggetti annidati. -> -> Inoltre, `shouldComponentUpdate` rimanda gli aggiornamenti per l'intero sotto albero di componenti. Assicurati che tutti i componenti figli siano anch'essi "puri". diff --git a/docs/docs/10.8-pure-render-mixin.ja-JP.md b/docs/docs/10.8-pure-render-mixin.ja-JP.md deleted file mode 100644 index d0bc8b8e77..0000000000 --- a/docs/docs/10.8-pure-render-mixin.ja-JP.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -id: pure-render-mixin -title: PureRenderMixin -permalink: docs/pure-render-mixin-ja-JP.html -prev: update-ja-JP.html -next: perf-ja-JP.html ---- - -Reactコンポーネントのrender関数が「ピュア」である(言い換えると、同じpropsやstateが与えられた時に同じ結果をレンダリングする)場合は、いくつかのケースでパフォーマンスをあげるためにこのミックスインを使用することができます。 - -例: - -```js -var PureRenderMixin = require('react/addons').addons.PureRenderMixin; -React.createClass({ - mixins: [PureRenderMixin], - - render: function() { - return
                    foo
                    ; - } -}); -``` - -内部で、このミックスインは[shouldComponentUpdate](/react/docs/component-specs.html#updating-shouldcomponentupdate)を実行します。現在のpropsとstateを次のものと比較し、同様のものであれば、 `false` を返します。 - -> 注意: -> このミックスインはオブジェクトの比較のみを行います。それらが複雑なデータ構造を持っていた場合、深い位置における違いは見逃されることがあります。単純なpropsやstateをコンポーネントが持っている場合にのみ、使用してください。深いデータ構造が変更されることが分かっている場合は、 `forceUpdate()` を使用してください。または、ネストされたデータの比較を速く行うために[不変オブジェクト](https://facebook.github.io/immutable-js/)の使用を考えてみてください。 -> 更に、 `shouldComponentUpdate` は全てのコンポーネントのサブツリーのアップデートをスキップします。全ての子要素のコンポーネントもまた、「ピュア」であることを確認してください。 diff --git a/docs/docs/10.8-pure-render-mixin.ko-KR.md b/docs/docs/10.8-pure-render-mixin.ko-KR.md deleted file mode 100644 index 4fe4cce8c7..0000000000 --- a/docs/docs/10.8-pure-render-mixin.ko-KR.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -id: pure-render-mixin-ko-KR -title: PureRenderMixin -permalink: docs/pure-render-mixin-ko-KR.html -prev: update-ko-KR.html -next: perf-ko-KR.html ---- - -React 컴포넌트의 렌더 함수가 "pure"하다면 (다른 말로, props나 state에 같은 값이 주어질 때 같은 결과를 렌더한다면) 몇몇 경우엔 이 믹스인을 사용하여 성능을 향상시킬 수 있습니다. - -예제: - -```js -var PureRenderMixin = require('react-addons-pure-render-mixin'); -React.createClass({ - mixins: [PureRenderMixin], - - render: function() { - return
                    foo
                    ; - } -}); -``` - -내부적으로 믹스인은 현재의 props와 state를 다음 값과 비교하여 같다면 `false`를 반환하도록 [shouldComponentUpdate](/react/docs/component-specs-ko-KR.html#업데이트-시-shouldcomponentupdate)를 구현합니다. - -> 주의: -> -> 여기서는 객체에 대한 얕은(shallow) 비교만 합니다. 복잡한 데이터 구조를 가진 경우에는 깊은 부분의 차이에 대해 잘못된 false를 반환 할 수도 있습니다. 간단한 props와 state를 사용하는 컴포넌트에만 적용하거나 깊은 데이터 구조가 변경 되었을때는 `forceUpdate()`를 사용하세요. 아니면 중첩 데이터의 비교를 빠르고 용이하게 하기 위해 [immutable 객체](https://facebook.github.io/immutable-js/)의 도입을 고려해보세요. -> -> 또, `shouldComponentUpdate`는 컴포넌트 서브트리의 업데이트를 건너뜁니다. 모든 자식 컴포넌트들도 "pure"한지 확인하세요. diff --git a/docs/docs/10.8-pure-render-mixin.zh-CN.md b/docs/docs/10.8-pure-render-mixin.zh-CN.md deleted file mode 100644 index a767a0b1b0..0000000000 --- a/docs/docs/10.8-pure-render-mixin.zh-CN.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -id: pure-render-mixin-zh-CN -title: PureRenderMixin -permalink: docs/pure-render-mixin-zh-CN.html -prev: update-zh-CN.html -next: perf-zh-CN.html ---- - -如果你的 React 组件的 render 函数是 "纯净" 的(换句话说,它的渲染在给定相同的 props 和 state 时返回相同的结果),你可以使用这个 mixin 在某些情况下进行性能加速。 - -例子: - -```js -var PureRenderMixin = require('react-addons-pure-render-mixin'); -React.createClass({ - mixins: [PureRenderMixin], - - render: function() { - return
                    foo
                    ; - } -}); -``` - -使用 ES6 class 语法的例子: - -```js -import PureRenderMixin from 'react-addons-pure-render-mixin'; -class FooComponent extends React.Component { - constructor(props) { - super(props); - this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this); - } - - render() { - return
                    foo
                    ; - } -} -``` - -在内部, mixin 实现了 [shouldComponentUpdate](/react/docs/component-specs.html#updating-shouldcomponentupdate), 它对当前及下一步的 props 和 state 进行比较,并当相等时返回 `false`。 - -> 注意: -> -> 它仅仅浅比较对象。如果包含了复杂的对象,可能会对于深层的不同产生 false-negatives。只 mix 到那些含有简单 props 和 state 的组件,或者在你知道深层对象改变时使用 `forceUpdate()` 。或者,考虑使用[immutable objects](https://facebook.github.io/immutable-js/) 来促进快速的嵌套数据比较。 -> -> 此外, `shouldComponentUpdate` 跳过了整个子树的更新。确保所有的子组件都是 "纯净" 的。 diff --git a/docs/docs/10.9-perf.it-IT.md b/docs/docs/10.9-perf.it-IT.md deleted file mode 100644 index 8d9ed17e7e..0000000000 --- a/docs/docs/10.9-perf.it-IT.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -id: perf-it-IT -title: Strumenti per la Performance -permalink: docs/perf-it-IT.html -prev: pure-render-mixin-it-IT.html -next: advanced-performance-it-IT.html ---- - -React è solitamente assai veloce. Tuttavia, in situazioni nelle quali devi spremere fino all'ultima goccia di prestazioni dalla tua applicazione, fornisce un hook [shouldComponentUpdate](/react/docs/component-specs.html#updating-shouldcomponentupdate) nel quale puoi aggiungere controlli di ottimizzazione per l'algoritmo di confronto di React. - -Oltre a darti una panoramica sulle prestazioni generali della tua applicazione, ReactPerf è uno strumento di profilazione che ti dice esattamente dove è necessario aggiungere questi hook. - -> Nota: -> -> La build di sviluppo di React è più lenta della build di produzione, per via di tutta la logica aggiuntiva per fornire, ad esempio, gli avvisi amichevoli di React nella console (eliminati dalla build di produzione). Pertanto, il profilatore serve soltanto ad indicare le parti _relativamente_ costose della tua applicazione. - -## API Generale - -L'oggetto `Perf` documentato di seguito è esposto come `React.addons.Perf` quando si usa la build `react-with-addons.js` in modalità di sviluppo. - -### `Perf.start()` and `Perf.stop()` -Avvia/interrompe la misurazione. Le operazioni React intermedie sono registrate per analisi in seguito. Le operazioni che hanno impiegato un tempo trascurabile vengono ignorate. - -Dopo l'interruzione, dovrai chiamare `Perf.getLastMeasurements()` (descritta in seguito) per ottenere le misurazioni. - -### `Perf.printInclusive(measurements)` -Stampa il tempo complessivo impiegato. Se non vengono passati argomenti, stampa tutte le misurazioni dall'ultima registrazione. Stampa una tabella gradevolmente formattata nella console, come segue: - -![](/react/img/docs/perf-inclusive.png) - -### `Perf.printExclusive(measurements)` -I tempi "esclusivi" non includono il tempo impiegato a montare i componenti: processare le proprietà, `getInitialState`, chiamare `componentWillMount` e `componentDidMount`, etc. - -![](/react/img/docs/perf-exclusive.png) - -### `Perf.printWasted(measurements)` - -**La parte più utile in assoluto del profilatore**. - -Il tempo "sprecato" è impiegato nei componenti che non hanno di fatto visualizzato nulla, ad es. il rendering è rimasto inalterato, quindi il DOM non è stato toccato. - -![](/react/img/docs/perf-wasted.png) - -### `Perf.printDOM(measurements)` -Stampa le manipolazioni sottostanti del DOM, ad es. "imposta innerHTML" e "rimuovi". - -![](/react/img/docs/perf-dom.png) - -## API Avanzata - -I metodi di stampa precedenti utilizzano `Perf.getLastMeasurements()` per effettuare una gradevole stampa dei risultati. - -### `Perf.getLastMeasurements()` -Ottieni l'array delle misurazioni dall'ultima sessione di avvio-interruzione. L'array contiene oggetti, ciascuno dei quali assomiglia a quanto segue: - -```js -{ - // I termini "inclusive" ed "exclusive" sono spiegati in seguito - "exclusive": {}, - // '.0.0' è l'identificativo React del nodo - "inclusive": {".0.0": 0.0670000008540228, ".0": 0.3259999939473346}, - "render": {".0": 0.036999990697950125, ".0.0": 0.010000003385357559}, - // Numero di istanze - "counts": {".0": 1, ".0.0": 1}, - // Scritture sul DOM - "writes": {}, - // Informazioni aggiuntive per il debug - "displayNames": { - ".0": {"current": "App", "owner": ""}, - ".0.0": {"current": "Box", "owner": "App"} - }, - "totalTime": 0.48499999684281647 -} -``` diff --git a/docs/docs/10.9-perf.ja-JP.md b/docs/docs/10.9-perf.ja-JP.md deleted file mode 100644 index a2431cf251..0000000000 --- a/docs/docs/10.9-perf.ja-JP.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -id: perf -title: パフォーマンスツール -permalink: docs/perf-ja-JP.html -prev: pure-render-mixin-ja-JP.html -next: advanced-performance-ja-JP.html ---- - -Reactは普通、従来の枠を超えてとても速いです。しかし、アプリケーションにおいて、少しでもパフォーマンスを上げようという状況では、Reactの差分を取るアルゴリズムを最大限活用するヒントが得られる、[shouldComponentUpdate](/react/docs/component-specs.html#updating-shouldcomponentupdate)のフックを提供します。 - -アプリケーション全体のパフォーマンスについての要約を得ることに加えて、ReactPerfはそれらのフックを実際にはどこに配置する必要があるか教えてくれるプロファイリングツールでもあります。 - -> 注意: -> Reactの開発版のビルドは与えられた外部ロジックのためにプロダクション版のビルドよりも遅くなります。例えば、Reactのフレンドリーコンソールの警告(プロダクション版のビルドにおいては警告が出ません)のように。それゆえ、プロファイラは *比較的* コストがかかっている箇所のみを指し示します。 - -## 一般的なAPI - -ここに記述されている `Perf` オブジェクトは `react-with-addons.js` を開発版でビルドしたものを使用する際に `React.addons.Perf` として表されます。 - -### `Perf.start()` と `Perf.stop()` -測定の開始/終了です。その間のReactの操作は以下のような分析のために記録されます。あまり時間を使わない操作は無視されます。 - -停止した後、あなたは、測定結果を得るために `Perf.getLastMeasurements()` (後述)が必要になります。 - -### `Perf.printInclusive(measurements)` -かかった全ての時間を出力します。引数が渡されなかった場合は、デフォルトで最後の測定から全ての測定が行われます。これは以下のように、コンソールに綺麗にフォーマットされたテーブルを出力します。 - -![](/react/img/docs/perf-inclusive.png) - -### `Perf.printExclusive(measurements)` -「占有」時間はコンポーネントをマウントするのにかかった時間を含みません。プロパティの処理、 `getInitialState` , `componentWillMount` や `componentDidMount` の呼び出しなどは含みます。 - -![](/react/img/docs/perf-exclusive.png) - -### `Perf.printWasted(measurements)` - -**プロファイラの最も有用な箇所です**。 - -「無駄な」時間はコンポーネントが実際には何もレンダリングしていないのにかかっている時間です。例えば、同じものをレンダリングしたので、DOMが触られなかったような場合です。 - -![](/react/img/docs/perf-wasted.png) - -### `Perf.printDOM(measurements)` -以下のような、DOMの操作を出力します。例えば、"set innerHTML"や"remove"といったものです。 - -![](/react/img/docs/perf-dom.png) - -## 先進的なAPI - -上記の出力メソッドは結果をプリティプリントするのに `Perf.getLastMeasurements()` を使用しています。 - -### `Perf.getLastMeasurements()` -最後の開始と終了のセッションから測定の配列を取得します。配列は以下のようなオブジェクトを含みます。 - -```js -{ - // "inclusive"と"exclusive"の期間は以下で説明されています - "exclusive": {}, - // '.0.0' はノードのReact ID - "inclusive": {".0.0": 0.0670000008540228, ".0": 0.3259999939473346}, - "render": {".0": 0.036999990697950125, ".0.0": 0.010000003385357559}, - // インスタンスの数 - "counts": {".0": 1, ".0.0": 1}, - // 触ったDOM - "writes": {}, - // 追加のデバッグ情報 - "displayNames": { - ".0": {"current": "App", "owner": ""}, - ".0.0": {"current": "Box", "owner": "App"} - }, - "totalTime": 0.48499999684281647 -} -``` diff --git a/docs/docs/10.9-perf.ko-KR.md b/docs/docs/10.9-perf.ko-KR.md deleted file mode 100644 index ab639bb425..0000000000 --- a/docs/docs/10.9-perf.ko-KR.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -id: perf-ko-KR -title: 성능 도구 -permalink: docs/perf-ko-KR.html -prev: pure-render-mixin-ko-KR.html -next: advanced-performance-ko-KR.html ---- - -React는 보통 처음에는 꽤 빠릅니다. 하지만 모든 성능을 짜내야 하는 상황일 때를 위해, React는 [shouldComponentUpdate](/react/docs/component-specs-ko-KR.html#업데이트-시-shouldcomponentupdate) 훅을 제공해 React의 diff 알고리즘을 위한 최적화 힌트를 추가할 수 있습니다. - -덧붙여 앱의 전반적인 성능의 개요도 제공합니다. ReactPerf는 프로파일링 도구로 정확히 어디에 훅이 필요한지 알려줍니다. - -> 주의: -> -> React의 개발 빌드는 제공되는 추가 기능으로 인해 프로덕션 빌드보다 느립니다. 추가 기능에는 React의 친절한 콘솔 경고같은 것이 있습니다.(이는 프로덕션 빌드에서는 제거 됩니다) 따라서, 프로파일러는 앱의 _상대적으로_ 비싼 부분만 표시하도록 합니다. - -## 일반 API - -여기에서 설명하는 `Perf` 객체는 `require('react-addons-perf')`로 노출되고 React 개발 모드에서만 사용할 수 있습니다. 이 번들을 프로덕션에서 앱과 같이 빌드하시면 안됩니다. - -### `Perf.start()`와 `Perf.stop()` -측정을 시작/정지합니다. 그 사이의 React 연산은 밑에 있는 분석을 하기위해 기록됩니다. 미미한 양의 연산은 무시됩니다. - -종료 후, 측정을 하기위해서는 이후에 설명할 `Perf.getLastMeasurements()`가 필요합니다. - -### `Perf.printInclusive(measurements)` -전 수행 시간을 출력합니다. 인자가 넘겨지지 않으면, 기본값은 지난 기록부터의 모든 측정이 됩니다. 이 출력은 밑에 있는 것처럼 콘솔에서 깔끔한 테이블로 그려집니다. - -![](/react/img/docs/perf-inclusive.png) - -### `Perf.printExclusive(measurements)` -컴포넌트를 마운트하는 시간을 포함하지 않은 "exclusive" 시간입니다. 여기에는 props 연산, `getInitialState`, `componentWillMount` 호출, `componentDidMount`등이 포함됩니다. - -![](/react/img/docs/perf-exclusive.png) - -### `Perf.printWasted(measurements)` - -**프로파일러에서 가장 유용한 부분입니다**. - -렌더가 같아서, DOM을 변경(touch)하지 않는 경우같은 실제로는 아무것도 렌더하지 않는 컴포넌트가 사용하는 "낭비되는" 시간을 출력합니다. - -![](/react/img/docs/perf-wasted.png) - -### `Perf.printDOM(measurements)` -"set innerHTML"이나 "remove"같은 기저의 DOM 조작을 출력합니다. - -![](/react/img/docs/perf-dom.png) - -## 고급 API - -위의 출력 메소드에 `Perf.getLastMeasurements()`를 사용해 결과를 이쁘게 출력합니다. - -### `Perf.getLastMeasurements()` -마지막 start-stop 세션에서 측정들의 배열을 가져옵니다. 이 배열은 이런 객체들을 가지고 있습니다. - -```js -{ - // 용어 "inclusive"와 "exclusive"는 위에서 설명했음 - "exclusive": {}, - // '.0.0'는 노드의 React ID - "inclusive": {".0.0": 0.0670000008540228, ".0": 0.3259999939473346}, - "render": {".0": 0.036999990697950125, ".0.0": 0.010000003385357559}, - // 인스턴스의 수 - "counts": {".0": 1, ".0.0": 1}, - // DOM 변경(touch) - "writes": {}, - // 추가 디버깅 정보 - "displayNames": { - ".0": {"current": "App", "owner": ""}, - ".0.0": {"current": "Box", "owner": "App"} - }, - "totalTime": 0.48499999684281647 -} -``` diff --git a/docs/docs/10.9-perf.md b/docs/docs/10.9-perf.md deleted file mode 100644 index 69ace66e67..0000000000 --- a/docs/docs/10.9-perf.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -id: perf -title: Performance Tools -permalink: docs/perf.html -prev: pure-render-mixin.html -next: shallow-compare.html ---- - -React is usually quite fast out of the box. However, in situations where you need to squeeze every ounce of performance out of your app, it provides a [shouldComponentUpdate](/react/docs/component-specs.html#updating-shouldcomponentupdate) hook where you can add optimization hints to React's diff algorithm. - -In addition to giving you an overview of your app's overall performance, ReactPerf is a profiling tool that tells you exactly where you need to put these hooks. - -See these two articles by the [Benchling Engineering Team](http://benchling.engineering) for a in-depth introduction to performance tooling: ["Performance Engineering with React"](http://benchling.engineering/performance-engineering-with-react/) and ["A Deep Dive into React Perf Debugging"](http://benchling.engineering/deep-dive-react-perf-debugging/)! - -## Development vs. Production Builds - -If you're benchmarking or seeing performance problems in your React apps, make sure you're testing with the [minified production build](/react/downloads.html). The development build includes extra warnings that are helpful when building your apps, but it is slower due to the extra bookkeeping it does. - -However, the perf tools described on this page only work when using the development build of React. Therefore, the profiler only serves to indicate the _relatively_ expensive parts of your app. - -## General API - -The `Perf` object documented here is exposed as `require('react-addons-perf')` and can be used with React in development mode only. You should not include this bundle when building your app for production. - -### `Perf.start()` and `Perf.stop()` -Start/stop the measurement. The React operations in-between are recorded for analyses below. Operations that took an insignificant amount of time are ignored. - -After stopping, you will need `Perf.getLastMeasurements()` (described below) to get the measurements. - -### `Perf.printInclusive(measurements)` -Prints the overall time taken. If no argument's passed, defaults to all the measurements from the last recording. This prints a nicely formatted table in the console, like so: - -![](/react/img/docs/perf-inclusive.png) - -### `Perf.printExclusive(measurements)` -"Exclusive" times don't include the times taken to mount the components: processing props, `getInitialState`, call `componentWillMount` and `componentDidMount`, etc. - -![](/react/img/docs/perf-exclusive.png) - -### `Perf.printWasted(measurements)` - -**The most useful part of the profiler**. - -"Wasted" time is spent on components that didn't actually render anything, e.g. the render stayed the same, so the DOM wasn't touched. - -![](/react/img/docs/perf-wasted.png) - -### `Perf.printOperations(measurements)` -Prints the underlying DOM manipulations, e.g. "set innerHTML" and "remove". - -![](/react/img/docs/perf-dom.png) - -### `Perf.printDOM(measurements)` - -This method has been renamed to `printOperations()` which is described in the previous paragraph. Currently `printDOM()` still exists as an alias but it prints a deprecation warning and will eventually be removed. - -## Advanced API - -The above print methods use `Perf.getLastMeasurements()` to pretty-print the result. - -### `Perf.getLastMeasurements()` -Get the opaque data structure describing measurements from the last start-stop session. You can save it and pass it to the methods above to analyze past measurements. - -Don't rely on the exact format of the return value because it may change in minor releases. We will update the documentation if the return value format becomes a supported part of the public API. diff --git a/docs/docs/10.9-perf.zh-CN.md b/docs/docs/10.9-perf.zh-CN.md deleted file mode 100644 index 621404670e..0000000000 --- a/docs/docs/10.9-perf.zh-CN.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -id: perf-zh-CN -title: 性能工具 -permalink: docs/perf-zh-CN.html -prev: pure-render-mixin-zh-CN.html -next: shallow-compare-zh-CN.html ---- - -React 通常是相当快的。然而,在你需要压榨你的 app 的每一分性能的情况下,它提供了一个[shouldComponentUpdate](/react/docs/component-specs.html#updating-shouldcomponentupdate) 钩子,在此你可以添加优化提示到 React 的 diff 算法里。 - -除了给予你一个你的 app 的整体性能概览外,ReactPerf 还是一个准确告诉你,你需要在哪里放置这些钩子的分析工具。 - -## General API - -这里陈述的 `Perf` 对象被用 `require('react-addons-perf')` 暴露,并且只能被使用在 React 的开发模式。你不应在生产环境下在你的 app 包含这个包。 - -> 注意: -> -> 开发版的 React 慢于生产版,因为所有额外提供的逻辑,例如,React 的友好的控制台警告 (在生产版中被除去)。因此,分析工具仅服务于指示你的 app _相对_ 昂贵的部分。 - -### `Perf.start()` and `Perf.stop()` -开始/停止测量。其间的React操作被记录用于之后的分析。产生无关紧要时间的操作被忽略。 - -在停止以后,你将需要 `Perf.getLastMeasurements()` (下面将介绍)来获取测量结果。 - -### `Perf.printInclusive(measurements)` -打印总体花费的时间。如果没有传入参数,默认是从上次记录的所有测量数据。它在控制台里打印良好格式化的结果,像这样: - -![](/react/img/docs/perf-inclusive.png) - -### `Perf.printExclusive(measurements)` -"独占的"时间不包括花费于加载组件的时间: 处理 props, `getInitialState`, 调用 `componentWillMount` 及 `componentDidMount`, 等等。 - -![](/react/img/docs/perf-exclusive.png) - -### `Perf.printWasted(measurements)` - -**分析工具里最有用的部分**. - -"垃圾"时间是花费在组件上实际没有绘制任何东西的时间,例如渲染结果总是相同,所以 DOM 没有被触碰到。 - -![](/react/img/docs/perf-wasted.png) - -### `Perf.printDOM(measurements)` -打印底层的 DOM 操纵,例如 "set innerHTML" 和 "remove". - -![](/react/img/docs/perf-dom.png) - -## Advanced API - -以上的打印方法使用 `Perf.getLastMeasurements()` 来美观的打印结果。 - -### `Perf.getLastMeasurements()` -从最后的 start-stop 会话获取测量数据数据。这个数组包含对象,每个看起来像这样: - -```js -{ - // The term "inclusive" and "exclusive" are explained below - "exclusive": {}, - // '.0.0' is the React ID of the node - "inclusive": {".0.0": 0.0670000008540228, ".0": 0.3259999939473346}, - "render": {".0": 0.036999990697950125, ".0.0": 0.010000003385357559}, - // Number of instances - "counts": {".0": 1, ".0.0": 1}, - // DOM touches - "writes": {}, - // Extra debugging info - "displayNames": { - ".0": {"current": "App", "owner": ""}, - ".0.0": {"current": "Box", "owner": "App"} - }, - "totalTime": 0.48499999684281647 -} -``` diff --git a/docs/docs/11-advanced-performance.it-IT.md b/docs/docs/11-advanced-performance.it-IT.md deleted file mode 100644 index 0841a3b831..0000000000 --- a/docs/docs/11-advanced-performance.it-IT.md +++ /dev/null @@ -1,207 +0,0 @@ ---- -id: advanced-performance-it-IT -title: Performance Avanzata -permalink: docs/advanced-performance-it-IT.html -prev: perf-it-IT.html ---- - -Una tra le prime domande che la gente si pone quando considera React per un progetto è se l'applicazione sarà altrettanto veloce e scattante di una versione equivalente non basata su React. L'idea di ripetere il rendering di un intero sottoalbero di componenti in risposta a ciascun cambiamento dello stato rende la gente curiosa se questo processo influisce negativamente sulle prestazioni. React utilizza diverse tecniche intelligenti per minimizzare il numero di operazioni costose sul DOM richieste dall'aggiornamento della UI. - -## Evitare di riconciliare il DOM - -React fa uso di un *DOM virtuale*, che è un descrittore di un sottoalbero DOM visualizzato nel browser. Questa rappresentazione parallela permette a React di evitare di creare nodi DOM e accedere nodi esistenti, che è di gran lunga più lento di operazioni su oggetti JavaScript. Quando le proprietà di un componente o il suo stato cambiano, React decide se un'aggiornamento effettivo del DOM sia necessario costruendo un nuovo virtual DOM e confrontandolo con quello vecchio. Solo nel caso in cui non siano uguali, React [riconcilierà](/react/docs/reconciliation.html) il DOM, applicando il minor numero di mutamenti possibile. - -In aggiunta a questo, React offre una funzione per il ciclo di vita del componente, `shouldComponentUpdate`, che viene scatenata prima che il processo di ri-rendering cominci (il confronto del DOM virtuale e una possibile eventuale riconciliazione del DOM), dando allo sviluppatore la possibilità di cortocircuitare questo processo. L'implementazione predefinita di questa funzione restituisce `true`, lasciando che React effettui l'aggiornamento: - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - return true; -} -``` - -Tieni in mente che React invocherà questa funzione abbastanza spesso, quindi l'implementazione deve essere veloce. - -Supponiamo che hai un'applicazione di messaggistica con parecchi thread di conversazioni. Supponi che solo uno dei thread sia cambiato. Se implementassimo `shouldComponentUpdate` sul componente `ChatThread`, React potrebbe saltare la fase di rendering per gli altri thread: - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - // TODO: restituisci true se il thread attuale è diverso - // da quello precedente. -} -``` - -Quindi, riassumendo, React evita di effettuare operazioni costose sul DOM richieste a riconciliare sottoalberi del DOM, permettendo all'utente di cortocircuitare il processo usando `shouldComponentUpdate`, e, per i casi in cui si debba aggiornare, confrontando i DOM virtuali. - -## shouldComponentUpdate in azione - -Ecco un sottoalbero di componenti. Per ciascuno di essi viene indicato cosa `shouldComponentUpdate` ha restituito e se i DOM virtuali siano equivalenti o meno. Infine, il colore del cerchio indica se il componente sia stato riconciliato o meno. - -
                    - -Nell'esempio precedente, dal momento che `shouldComponentUpdate` ha restituito `false` per il sottoalbero di radice C2, React non ha avuto bisogno di generare il nuovo DOM virtuale, e quindi non ha nemmeno avuto bisogno di riconciliare il DOM. Nota che React non ha nemmeno avuto bisogno di invocare `shouldComponentUpdate` su C4 e C5. - -Per C1 e C3, `shouldComponentUpdate` ha restituito `true`, quindi React è dovuto scendere giù fino alle foglie e controllarle. Per C6 ha restituito `true`; dal momento che i DOM virtuali non erano equivalenti, ha dovuto riconciliare il DOM. -L'ultimo caso interessante è C8. Per questo nodo React ha dovuto calcolare il DOM virtuale, ma dal momento che era uguale al vecchio, non ha dovuto riconciliare il suo DOM. - -Nota che React ha dovuto effettuare mutazioni del DOM soltanto per C6, che era inevitabile. Per C8, lo ha evitato confrontando i DOM virtuali, e per il sottoalbero di C2 e C7, non ha neppure dovuto calcolare il DOM virtuale in quanto è stato esonerato da `shouldComponentUpdate`. - -Quindi, come dovremmo implementare `shouldComponentUpdate`? Supponiamo di avere un componente che visualizza soltanto un valore stringa: - -```javascript -React.createClass({ - propTypes: { - value: React.PropTypes.string.isRequired - }, - - render: function() { - return
                    {this.props.value}
                    ; - } -}); -``` - -Potremmo facilmente implementare `shouldComponentUpdate` come segue: - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - return this.props.value !== nextProps.value; -} -``` - -Finora tutto a posto, maneggiare queste semplici strutture proprietà e stato è molto facile. Potremmo anche generalizzare un'implementazione basata sull'uguaglianza superficiale e farne il mix dentro i componenti. Infatti, React fornisce già una tale implementazione: [PureRenderMixin](/react/docs/pure-render-mixin.html). - -Ma che succede se le proprietà o lo stato del tuo componente sono strutture dati mutevoli? Supponiamo che la proprietà che il componente riceve sia, anziché una stringa come `'bar'`, un oggetto JavaScript che contiene una stringa, come `{ foo: 'bar' }`: - -```javascript -React.createClass({ - propTypes: { - value: React.PropTypes.object.isRequired - }, - - render: function() { - return
                    {this.props.value.foo}
                    ; - } -}); -``` - -L'implementazione di `shouldComponentUpdate` che avevamo prima non funzionerebbe sempre come ci aspettiamo: - -```javascript -// assumiamo che this.props.value sia { foo: 'bar' } -// assumiamo che nextProps.value sia { foo: 'bar' }, -// ma questo riferimento è diverso da this.props.value -this.props.value !== nextProps.value; // true -``` - -Il problema è che `shouldComponentUpdate` restituirà `true` quando la proprietà non è in realtà cambiata. Per risolvere questo problema, potremmo proporre questa implementazione alternativa: - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - return this.props.value.foo !== nextProps.value.foo; -} -``` - -In breve, abbiamo finito per effettuare un confronto in profondità per assicurarci di accorgerci correttamente dei cambiamenti. In termini di prestazioni, questo approccio è molto costoso. Non scala in quanto dovremmo scrivere codice diverso per valutare l'uguaglianza in profondità per ciascun modello. Inoltre, potrebbe anche non funzionare per nulla se non gestiamo correttamente i riferimenti agli oggetti. Supponiamo che il componente sia usato da un genitore: - -```javascript -React.createClass({ - getInitialState: function() { - return { value: { foo: 'bar' } }; - }, - - onClick: function() { - var value = this.state.value; - value.foo += 'bar'; // ANTI-PATTERN! - this.setState({ value: value }); - }, - - render: function() { - return ( -
                    - - Click me -
                    - ); - } -}); -``` - -La prima volta che viene effettuato il rendering del componente interno, la sua proprietà value avrà il valore `{ foo: 'bar' }`. Se l'utente clicca l'ancora, lo stato del componente genitore sarà aggiornato a `{ value: { foo: 'barbar' } }`, scatenando il processo di ri-rendering sul componente interno, il quale riceverà `{ foo: 'barbar' }` come il nuovo valore della proprietà. - -Il problema è che, dal momento che il genitore e il componente interno condividono un riferimento allo stesso oggetto, quando l'oggetto viene modificato nella riga 2 della funzione `onClick`, la proprietà che il componente interno possedeva cambierà anch'essa. Quindi, quando il processo di ri-rendering inizia, e `shouldComponentUpdate` viene invocato, `this.props.value.foo` sarà uguale a `nextProps.value.foo`, perché infatti, `this.props.value` si riferisce allo stesso oggetto di `nextProps.value`. - -Di conseguenza, dal momento che non ci accorgiamo del cambiamento della proprietà e cortocircuitiamo il processo di ri-rendering, la UI non sarà aggiornata da `'bar'` a `'barbar'`. - -## Immutable-js viene in nostro soccorso - -[Immutable-js](https://github.com/facebook/immutable-js) è una libreria di collezioni JavaScript scritta da Lee Byron, che Facebook ha recentemente rilasciato come open source. Fornisce collezioni *immutabili e persistenti* attraverso *condivisione strutturale*. Vediamo cosa significano queste proprietà: - -* *Immutabile*: una volta creata, una collezione non può essere alterata in un momento successivo. -* *Persistente*: nuove collezioni possono essere create da una collezione precedente e una mutazione come un assegnamento. La collezione originale è ancora valida dopo che la nuova collezione è stata creata. -* *Condivisione Strutturale*: nuove collezioni sono create riutilizzando quanto più possibile della stessa struttura della collezione originale, riducendo le operazioni di copia al minimo, per ottenere efficienza spaziale e prestazioni accettabili. Se la nuova collezione è identica all'originale, l'originale è spesso restituita. - -L'immutabilità ci permette di tenere traccia dei cambiamenti in modo economico; un cambiamento risulterà sempre in un nuovo oggetto, quindi dobbiamo soltanto controllare se il riferimento all'oggeto sia cambiato. Ad esempio, in questo codice regolare JavaScript: - -```javascript -var x = { foo: "bar" }; -var y = x; -y.foo = "baz"; -x === y; // true -``` - -Sebbene `y` sia stato modificato, dal momento che si tratta di un riferimento allo stesso oggetto di `x`, questo confronto restituisce `true`. Tuttavia, questo codice potrebbe essere scritto usando immutable-js come segue: - -```javascript -var SomeRecord = Immutable.Record({ foo: null }); -var x = new SomeRecord({ foo: 'bar' }); -var y = x.set('foo', 'baz'); -x === y; // false -``` - -In questo caso, poiché un nuovo riferimento è restituito quando si modifica `x`, possiamo assumere in tutta sicurezza che `x` sia cambiato. - -Un'altra maniera possibile di tener traccia dei cambiamenti potrebbe essere il dirty checking, ovvero usare un flag impostato dai metodi setter. Un problema con questo approccio è che ti forza ad usare i setter e scrivere un sacco di codice aggiuntivo, oppure instrumentare in qualche modo le tue classi. In alternativa, puoi effettuare una copia profonda dell'oggetto immediatamente prima della mutazione ed effettuare un confronto in profondità per determinare se vi è stato un cambiamento oppure no. Un problema con questo approccio è che sia deepCopy che deepCompare sono operazioni costose. - -Quindi, le strutture dati Immutable ti forniscono una maniera economica e concisa di osservare i cambiamenti degli oggetti, che è tutto ciò che ci serve per implementare `shouldComponentUpdate`. Pertanto, se modelliamo gli attributi delle proprietà e dello stato usando le astrazioni fornite da immutable-js saremo in grado di usare `PureRenderMixin` e ottenere un grande aumento di prestazioni. - -## Immutable-js e Flux - -Se stai usando [Flux](https://facebook.github.io/flux/), dovresti cominciare a scrivere i tuoi store usando immutable-js. Dài un'occhiata alla [API completa](https://facebook.github.io/immutable-js/docs/#/). - -Vediamo una delle possibili maniere di modellare l'esempio dei thread usando strutture dati Immutable. Anzitutto, dobbiamo definire un `Record` per ciascuna delle entità che desideriamo modellare. I Record sono semplicemente contenitori immutabili che contengono valori per un insieme specifico di campi: - -```javascript -var User = Immutable.Record({ - id: undefined, - name: undefined, - email: undefined -}); - -var Message = Immutable.Record({ - timestamp: new Date(), - sender: undefined, - text: '' -}); -``` - -La funzione `Record` riceve un oggetto che definisce i campi che l'oggetto possiede e i loro valori predefiniti. - -Lo *store* dei messaggi potrebbe tenere traccia degli utenti e dei messaggi usando due liste: - -```javascript -this.users = Immutable.List(); -this.messages = Immutable.List(); -``` - -Dovrebbe essere abbastanza banale implementare funzioni che gestiscono ciascun tipo di *payload*. Ad esempio, quando lo store vede un payload che rappresenta un messaggio, possiamo semplicemente creare un nuovo record e metterlo in coda alla lista di messaggi: - -```javascript -this.messages = this.messages.push(new Message({ - timestamp: payload.timestamp, - sender: payload.sender, - text: payload.text -}); -``` - -Nota che dal momento che le strutture dati sono immutabili, dobbiamo assegnare il valore di ritorno del metodo push a `this.messages`. - -Dal punto di vista di React, se usiamo strutture dati immutable-js anche per contenere lo stato del componente, possiamo fare il mix di `PureRenderMixin` in tutti i nostri componenti e cortocircuitare il processo di ri-rendering. diff --git a/docs/docs/11-advanced-performance.ja-JP.md b/docs/docs/11-advanced-performance.ja-JP.md deleted file mode 100644 index 0df476c813..0000000000 --- a/docs/docs/11-advanced-performance.ja-JP.md +++ /dev/null @@ -1,205 +0,0 @@ ---- -id: advanced-performance -title: 先進的なパフォーマンス -permalink: docs/advanced-performance-ja-JP.html -prev: perf-ja-JP.html ---- - -Reactをプロジェクトで使用しようとする際にまず最初に気になるのは、アプリケーションがReactを使用しないバージョンと比べて、同じくらい速くてレスポンシブであるかどうかということです。ステータスの変更毎にレスポンスでコンポーネントのサブツリーの全てを再度レンダリングするという考え方によって、このプロセスがパフォーマンスにネガティブな影響を与えるのではないかと人々は不安に思います。ReactはUIを更新するのに必要な、コストのかかる多くのDOMの操作を最小限にするためのいくつかの賢い技術を使用します。 - -## DOMを一致させることを防ぐこと - -ReactはブラウザでレンダリングされるDOMのサブツリーの記述語である *virtual DOM* を使用しています。この2つの表現によってReactは、JavaScriptのオブジェクトの操作よりも遅い、DOMノードを作成したり存在しているDOMノードにアクセスすることを防いでいます。コンポーネントの `props` や `state` が変更された時、Reactは新しいvirtual DOMを構成して、それを古いものと比較することによって、実際のDOMの更新が必要かどうか決定します。それらが同じものでなかった場合にのみ、ReactはDOMを[一致](/react/docs/reconciliation.html)させ、最小限の変更を適用します。 -この最上位で、Reactはコンポーネントライフサイクルファンクションである `shouldComponentUpdate` を提供します。これは、再度レンダリングを行うプロセス(virtual DOMの比較と起こり得る最終的なDOMの一致)が始まる前に誘発されます。そして、開発者にこのプロセスの循環を短くすることを可能にします。デフォルトのこの関数の実行時にはReactが更新を行って、以下のように `true` が返ります。 - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - return true; -} -``` - -Reactがとても頻繁にこの関数を呼び出すので、実行が速いものである必要があることを頭に置いておいてください。 - -いくつかのチャットのスレッドを持つメッセージングのアプリケーションを持っていると仮定してください。そして、スレッドのうち1つだけが変更されたと考えてください。 `ChatThread` コンポーネントで `shouldComponentUpdate` を実行した際には、Reactは以下のように、他のスレッドのレンダリングステップをスキップできます。 - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - // TODO: 現在のチャットスレッドが以前のものと - // 異なっているかどうかをリターンする。 -} -``` - -つまり、要約すると、ReactはDOMのサブツリーを一致させる必要があるためにコストのかかるDOMの操作を実行するのを避けます。 `shouldComponentUpdate` を使用して、このプロセスを短縮することができます。そして、virtual DOMを比較して、更新すべきDOMだけを更新します。 - -## shouldComponentUpdate の実行 - -以下はコンポーネントのサブツリーです。1つ1つは `shouldComponentUpdate` が何をリターンするかとvirtual DOMが同じものであるかどうかを示しています。最終的には、円の色が、コンポーネントを一致させる必要があるかどうかを示しています。 - -
                    - -上記の例では、C2の上の `shouldComponentUpdate` が `false` を返しているので、Reactは新しいvirtual DOMを生成する必要はありません。そして、それゆえ、DOMを一致させる必要もありません。C4とC5についても、Reactが `shouldComponentUpdate` を実行する必要がないことに注意してください。 - -C1とC3の `shouldComponentUpdate` は `true` を返すので、Reactは葉の部分まで降りてそれらのチェックを行います。C6が `true` を返すので、virtual DOMが同じものではなくなり、DOMを一致させる必要があります。最後の興味深いケースはC8です。このノードについては、Reactはvirtual DOMを計算する必要がありますが、古いものと同じであるため、DOMと一致させる必要はありません。 - -ReactがDOMを変化させるのはC6だけであることに注意してください。これは避けられません。C8は、virtual DOMの比較から解放されています。C2のサブツリーとC7も同様です。`shouldComponentUpdate` から解放されているので、virtual DOMの比較を行う必要はありません。 - -それでは、私たちはどのように `shouldComponentUpdate` を実行すべきでしょうか?ある文字列の値をただレンダリングするコンポーネントの場合について見てみましょう。 - -```javascript -React.createClass({ - propTypes: { - value: React.PropTypes.string.isRequired - }, - - render: function() { - return
                    this.props.value
                    ; - } -}); -``` - -以下のように簡単に `shouldComponentUpdate` を実行することができます。 - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - return this.props.value !== nextProps.value; -} -``` - -これまでは順調でした。以上のような、単純なpropsやstateの構造を扱うことは簡単です。浅い同一性に基づいて実行したり、コンポーネントに組み込んだりもできます。実際、Reactはそのような実行のためのMixinを既に提供しています。[PureRenderMixin](/react/docs/pure-render-mixin-ja-JP.html)です。 - -しかし、コンポーネントのpropsやstateが変更される可能性がある場合はどうでしょうか?propが `bar` のような文字列ではなく、コンポーネント受け取ったものであると考えてみると、 `{ foo: 'bar' }` のような文字列を含んだJavaScriptのオブジェクトになります。 - -```javascript -React.createClass({ - propTypes: { - value: React.PropTypes.object.isRequired - }, - - render: function() { - return
                    this.props.value.foo
                    ; - } -}); -``` - -今までに述べてきた `shouldComponentUpdate` の実行は常に想定した通りに動くとは限りません。 - -```javascript -// this.props.value が { foo: 'bar' } であると仮定 -// nextProps.value が { foo: 'bar' } であると仮定 -// しかし、この参照は this.props.value とは異なります。 -this.props.value !== nextProps.value; // true -``` - -問題は、 `shouldComponentUpdate` が、propが実際には変化していない場合にも `true` を返すことです。これを修正するために、以下のような代替の実行を行うことができます。 - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - return this.props.value.foo !== nextProps.value.foo; -} -``` - -基本的には、厳密に変更を追跡することを明確にするために、深い比較を行うことになります。パフォーマンスの点では、このアプローチはとてもコストがかかります。これは、それぞれのモデルに対して間違った深い同一性のコードを書いているであろうときには、スケールしません。その最上部では、オブジェクトの参照を注意深く見ていなければ、動作しさえしません。以下のコンポーネントが親から使用されていると考えてください。 - -```javascript -React.createClass({ - getInitialState: function() { - return { value: { foo: 'bar' } }; - }, - - onClick: function() { - var value = this.state.value; - value.foo += 'bar'; // アンチパターン! - this.setState({ value: value }); - }, - - render: function() { - return ( -
                    - - Click me -
                    - ); - } -}); -``` - -はじめに、内部のコンポーネントがレンダリングされます。それは、valueというプロパティとして `{ foo: 'bar' }` を保有します。ユーザがアンカーをクリックした際には、親のコンポーネントのstateが `{ value: { foo: 'barbar' } }` にアップデートされるでしょう。そして、新しいvalueのプロパティとして、 `{ foo: 'barbar' }` を受け取る、内部のコンポーネントの再レンダリングのプロセスのトリガーとなります。 - -問題は、親と内部のコンポーネントが同じオブジェクトへの参照を共有していることです。オブジェクトが `onClick` 関数の2行目で変更された時には、内部のコンポーネントが保有しているプロパティが変更されるでしょう。そのため、再レンダリングのプロセスが始まった時と、 `shouldComponentUpdate` が呼び出された時には、 `this.props.value.foo` は `nextProps.value.foo` と同じものになるでしょう。そのため、実際は、 `this.props.value` は `nextProps.value` と同じオブジェクトを参照します。 - -結果として、プロパティの変更と再レンダリングのプロセスを省略ができなかったので、UIは `'bar'` から `'barbar'` にアップデートされないでしょう。 - -## 助けとなるImmutable-js - -[Immutable-js](https://github.com/facebook/immutable-js)はLee Byronによって作成されたJavaScriptのコレクションのライブラリです。Facebookが最近オープンソース化しました。これは、 *構造の共有* を通して、*不変の状態を保ち続ける* コレクションを提供します。以下のプロパティが何を意味するか見ていきましょう。 - -* *Immutable*: 一度作成されたら、コレクションは変更できません。 -* *Persistent*: 新しいコレクションは以前のコレクションかsetのような変化によってのみ作成されます。元となるコレクションは新しいコレクションが作成された後も使用可能です。 -* *Structural Sharing*: 新しいコレクションは元のコレクションとなるべく同じ構造を持って作成されます。パフォーマンスが効率的で許容できるものであるように、コピーを少なくします。新しいコレクションが元のものと同じである場合は、多くの場合元のものがリターンされます。 - -不変性によって、変更を追跡するコストが下がります。変更は常に新しいオブジェクトを生むので、オブジェクトの参照が変更されたかどうかを確認しさえすればよいのです。例えば、以下のような一般的なJavaScriptのコードにおいては、 - -```javascript -var x = { foo: "bar" }; -var y = x; -y.foo = "baz"; -x === y; // true -``` - -`y` は編集されていますが、`x` と同じオブジェクトを参照しているので、それらの比較は `true` を返します。しかし、以下のコードはimmutable-jsを使用すると以下のように記述されます。 - -```javascript -var SomeRecord = Immutable.Record({ foo: null }); -var x = new SomeRecord({ foo: 'bar' }); -var y = x.set('foo', 'baz'); -x === y; // false -``` - -このケースでは、 `x` を変更する時に新しい参照が返されているので、 `x` が変更されたことを安全に認識することができます。 - -変更を追跡する他の方法は、セッタによるフラグセットを保持することでダーティーチェックを行うことです。このアプローチの問題は、追加のコードを多く書いた場合やクラスの編集をいくつか行った場合でもセッタの使用が強制されることです。代わりに、変化の直前にオブジェクトをディープコピーし、変更が有ろうと無かろうと、その特定のために深い比較を行うことができます。このアプローチの問題は、ディープコピーと深い比較の両方とも、コストの高い操作であることです。 - -そのため、不変なデータ構造によって、オブジェクトの変更を追跡するためのコストの低く、冗長ではない方法が提供されます。私たちがすべきなのは `shouldComponentUpdate` を実行することだけです。それゆえ、immutable-jsに提供される抽象化を使用して、propsやstate属性を形作る場合は、 `PureRenderMixin` を使用して、パフォーマンスの向上を行うことができます。 - -## Immutable-js と Flux - -[Flux](https://facebook.github.io/flux/)を使用している場合には、immutable-jsを使用して書き直すべきです。[API一覧](https://facebook.github.io/immutable-js/docs/#/)をご覧ください。 - -不変のデータ構造を使用したスレッドの例を形作る、ある方法を見ていきましょう。はじめに、形作ろうとしているエンティティのそれぞれに `Record` を定義する必要が有ります。Record はあるフィールドのセットの値を保持している、ただの不変なコンテナです。 - -```javascript -var User = Immutable.Record({ - id: undefined, - name: undefined, - email: undefined -}); - -var Message = Immutable.Record({ - timestamp: new Date(), - sender: undefined, - text: '' -}); -``` - -`Record` 関数はオブジェクトが保有しているフィールドとデフォルトの値を定義するオブジェクトを受け取ります。 - -メッセージの *ストア* は以下のように2つのリストを使用して users と messages を追跡し続けることができます。 - -```javascript -this.users = Immutable.List(); -this.messages = Immutable.List(); -``` - -それぞれの *ペイロードの* 型を調査することはとても単純で、関数を実行するだけです。例えば、ストアが新しいメッセージを代表するペイロードを調べるときには、新しいレコードを作成し、それを以下のような messages のリストとして適用するだけです。 - -```javascript -this.messages = this.messages.push(new Message({ - timestamp: payload.timestamp, - sender: payload.sender, - text: payload.text -}); -``` - -データ構造が不変であることで、push関数の結果を `this.messages` にアサインする必要があることに注意してください。 - -Reactの側では、 immutable-js のデータ構造をコンポーネントの state を保持するために使用する場合は、 `PureRenderMixin` をコンポーネントにミックスし、再レンダリングのプロセスを短縮することもできます。 diff --git a/docs/docs/11-advanced-performance.ko-KR.md b/docs/docs/11-advanced-performance.ko-KR.md deleted file mode 100644 index 52ee1f35b9..0000000000 --- a/docs/docs/11-advanced-performance.ko-KR.md +++ /dev/null @@ -1,206 +0,0 @@ ---- -id: advanced-performance-ko-KR -title: 성능 심화 -permalink: docs/advanced-performance-ko-KR.html -prev: perf-ko-KR.html -next: context-ko-KR.html ---- - -React를 도입하려 할 때 많은 사람이 묻는 첫 번째 질문은 React를 사용하지 않을 때처럼 애플리케이션이 빠르고 반응성도 좋을 것이냐는 것입니다. 모든 상태변화에 대해 컴포넌트의 하위 트리를 전부 다시 렌더링하는 아이디어에 대해 사람들은 이 프로세스가 성능에 부정적인 영향을 줄 것으로 생각하지만, React는 여러 가지 영리한 방법을 통해 UI를 업데이트하는데 필요한 비싼 DOM 조작을 최소화합니다. - -## DOM 조정 회피 - -React는 브라우저에서 렌더된 DOM 하위 트리의 서술자 개념인 *가상의 DOM*을 사용합니다. 이 병렬적인 서술체는 React가 DOM 노드를 생성하거나 이미 존재하는 DOM 노드에 접근하는 것(JavaScript 객체를 조작하는 것보다 느리죠)을 피하게 해 줍니다. 컴포넌트의 props나 state가 변경되면 React는 새로운 가상의 DOM을 구성해 이전의 것과 비교해서 실제 DOM 업데이트가 필요한지 결정합니다. 가능한 적게 변화를 적용하기 위해, React는 둘이 다를 경우에만 DOM을 [조정](/react/docs/reconciliation-ko-KR.html)할 것입니다. - -이에 더해, React는 컴포넌트 생명주기 함수인 `shouldComponentUpdate`를 제공합니다. 이는 다시 렌더링하는 프로세스(가상 DOM 비교와 어쩌면 일어날 DOM 조정)가 일어나기 직전에 일어나며 개발자가 프로세스를 중단할 수 있게 합니다. 이 함수의 기본구현은 `true`를 반환해 React가 업데이트를 수행하도록 합니다. - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - return true; -} -``` - -React가 이 함수를 자주 호출한다는 것을 명심하십시오. 따라서 구현체는 빨라야 합니다. - -대화 스레드가 여럿 돌고 있는 메시지처리 애플리케이션을 생각해 봅시다. 오직 하나의 스레드만이 변경되었다고 가정해 보죠. `ChatThread`에 `shouldComponentUpdate`를 구현했다면 React는 다른 스레드의 렌더링 프로세스를 건너뛸 수 있습니다. - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - // TODO: 현재의 대화 스레드가 이전의 것과 다른지 아닌지를 반환한다 -} -``` - -정리하자면, React는 사용자가 `shouldComponentUpdate`를 사용해 렌더링 프로세스를 중단하고 가상의 DOM과 비교해 업데이트 여부를 결정해서 DOM의 하위 트리를 조정하는 비싼 DOM 조작을 피하도록 합니다. - -## shouldComponentUpdate 실전 - -다음은 컴포넌트의 하위 트리입니다. 각각은 `shouldComponentUpdate`의 반환값(SCU)과 가상의 DOM과의 동일성(vDOMEq)을 표시합니다. 마지막으로, 원의 색은 컴포넌트가 조정되었는지를 표시합니다. - -
                    - -위의 예시에서, C2를 루트로 하는 하위 트리에 대해 `shouldComponentUpdate`가 `false`를 반환했기 때문에 React는 새로운 가상의 DOM을 만들 필요가 없습니다. 따라서 DOM을 조정할 필요도 없습니다. React가 C4와 C5에는 `shouldComponentUpdate`를 요청하지도 않은 것을 확인하세요. - -C1과 C3의 `shouldComponentUpdate`가 `true`를 반환했기 때문에 React는 하위 노드로 내려가 그들을 확인합니다. C6는 `true`를 반환했네요; 이는 가상의 DOM과 같지 않기 때문에 DOM의 조정이 일어났습니다. 마지막으로 흥미로운 사례는 C8입니다. React가 이 노드를 위해 가상의 DOM을 작동했지만, 노드가 이전의 것과 일치했기 때문에 DOM의 조정을 일어나지 않았습니다. - -React가 C6에만 DOM 변경을 수행한 것을 확인하세요. 이는 필연적이었습니다. C8의 경우는, 가상의 DOM과 비교를 해 제외되었고, C2의 하위 트리와 C7은 `shouldComponentUpdate` 단계에서 제외되어 가상의 DOM은 구동조차 되지 않았습니다. - -자 그럼, 어떻게 `shouldComponentUpdate`를 구현해야 할까요? 문자열 값을 렌더하는 컴포넌트를 생각해보죠. - -```javascript -React.createClass({ - propTypes: { - value: React.PropTypes.string.isRequired - }, - - render: function() { - return
                    {this.props.value}
                    ; - } -}); -``` - -다음과 같이 간단히 `shouldComponentUpdate`를 구현해 볼 수 있습니다: - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - return this.props.value !== nextProps.value; -} -``` - -여기까지는 좋습니다. 간단한 props/state 구조를 다루기는 쉽습니다. 단순한 등식비교 구현을 일반화하고 이를 컴포넌트에 혼합할 수도 있습니다. 사실, React는 이미 그런 구현을 제공합니다: [PureRenderMixin](/react/docs/pure-render-mixin-ko-KR.html). - -하지만 만약 컴포넌트의 props나 state가 가변적인 데이터 구조로 되어 있다면 어떨까요? 컴포넌트의 prop으로 `'bar'`같은 문자열 대신에 `{ foo: 'bar' }`처럼 문자열을 포함한 JavaScript 객체를 전달받는다고 해봅시다. - -```javascript -React.createClass({ - propTypes: { - value: React.PropTypes.object.isRequired - }, - - render: function() { - return
                    {this.props.value.foo}
                    ; - } -}); -``` - -전에 구현했던 `shouldComponentUpdate`는 언제나 예상대로 작동하지 않을 것입니다: - -```javascript -// this.props.value가 { foo: 'bar' }라고 가정합니다 -// nextProps.value도 { foo: 'bar' }라고 가정하지만, -// 이 참조는 this.props.value와 다른 것입니다 -this.props.value !== nextProps.value; // true -``` - -문제는 prop이 실제로 변경되지 않았을 때도 `shouldComponentUpdate`가 `true`를 반환할 거라는 겁니다. 이를 해결하기 위한 대안으로, 아래와 같이 구현해 볼 수 있습니다: - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - return this.props.value.foo !== nextProps.value.foo; -} -``` - -기본적으로, 우리는 변경을 정확히 추적하기 위해서 깊은 비교를 해야 했습니다. 이 방법은 성능 면에서 제법 비쌉니다. 각각의 모델마다 다른 깊은 등식 코드를 작성해야 하므로 확장이 힘들어 집니다. 심지어 객체 참조를 신중히 관리하지 않는다면 작동하지도 않을 수 있습니다. 컴포넌트가 부모에 의해 다뤄지는 경우를 살펴보죠: - -```javascript -React.createClass({ - getInitialState: function() { - return { value: { foo: 'bar' } }; - }, - - onClick: function() { - var value = this.state.value; - value.foo += 'bar'; // 안티패턴 입니다! - this.setState({ value: value }); - }, - - render: function() { - return ( - - ); - } -}); -``` - -처음엔 내부 컴포넌트(``)가 `{ foo: 'bar' }`를 value prop으로 가진 채 렌더될 것입니다. 사용자가 앵커(``)를 클릭한다면 부모 컴포넌트의 state는 `{ value: { foo: 'barbar' } }`로 업데이트되고, 내부 컴포넌트 또한 `{ foo: 'barbar' }`를 새로운 value prop으로 전달받아 다시 렌더링 되는 프로세스가 일어날 것입니다. - -이 문제는 부모와 내부 컴포넌트가 같은 객체에 대한 참조를 공유하기 때문에 발생합니다. `onClick` 함수의 두 번째 줄에서 객체에 대한 변경이 일어날 때, 내부 컴포넌트의 prop도 변경될 것입니다. 따라서 다시 렌더링 되는 프로세스가 시작될 때 `shouldComponentUpdate`가 호출되고 `this.props.value.foo`가 `nextProps.value.foo`와 같게 됩니다. 실제로 `this.props.value`는 `nextProps.value`와 같은 객체이기 때문입니다. - -그에따라 prop의 변경을 놓치게 되어 다시 렌더링하는 프로세스가 중단되고, UI는 `'bar'`에서 `'barbar'`로 업데이트되지 않습니다. - -## 구원자 Immutable-js - -[Immutable-js](https://github.com/facebook/immutable-js)는 Lee Byron이 만들고 Facebook이 오픈소스화 한 JavaScript 컬렉션 라이브러리입니다. 이는 *구조의 공유(structural sharing)*를 통해 *불변의 영속적인(immutable persistent)* 컬렉션을 제공합니다. 이러한 속성이 무엇을 의미하는지 살펴보죠: - -* *불변성(Immutable)*: 컬렉션이 한번 생성되면, 이 후 다른 시점에 변경될 수 없습니다. -* *영속성(Persistent)*: 새로운 컬렉션이 이전의 컬렉션이나 셋(set) 같은 뮤테이션(mutation)에서 생성될 수 있습니다. 기존의 컬렉션은 새로운 컬렉션이 생성된 후에도 여전히 유효합니다. -* *구조의 공유(Structural Sharing)*: 새로운 컬렉션은 가능한 한 원래의 컬렉션과 같은 구조를 사용해 생성됩니다. 공간 효율성과 적절한 성능을 위해 복사를 최소화합니다. - -불변성은 변경의 추적을 비용을 줄여줍니다; 변경은 항상 새로운 객체에만 발생하기 때문에 객체에 대한 참조가 변경될 때만 확인하면 됩니다. 예를 들어 일반적인 이 JavaScript 코드에서는: - -```javascript -var x = { foo: "bar" }; -var y = x; -y.foo = "baz"; -x === y; // true -``` - -`y`가 수정되더라도 여전히 같은 객체인 `x`를 참조하고 있기 때문에, 이 비교는 `true`를 반환합니다. 하지만 이 코드를 immutable-js를 사용해 다음과 같이 작성할 수 있습니다: - -```javascript -var SomeRecord = Immutable.Record({ foo: null }); -var x = new SomeRecord({ foo: 'bar' }); -var y = x.set('foo', 'baz'); -x === y; // false -``` - -이 경우, `x`가 변경되면 새로운 참조가 반환되기 때문에, 우리는 안전하게 `x`가 변경되었을 것으로 추정할 수 있습니다. - -변경을 탐지할 수 있는 또 다른 방법은 세터(setter)에 의해 설정된 플래그를 더티 체킹(dirty checking)하는 것입니다. 이 방식의 문제는 당신이 세터를 사용할 뿐만 아니라 수많은 추가 코드를 작성하거나 어떻게든 클래스들을 인스트루먼트(instrument) 하도록 강요한다는 것입니다. 혹은 변경(mutations) 직전에 객체를 깊은 복사(deep copy) 한 뒤 깊은 비교(deep compare)를 수행해 변경 여부를 판단할 수 있습니다. 이 방식의 문제점은 deepCopy와 deepCompare 둘 다 비용이 많이 드는 연산이라는 것입니다. - -그래서 Immutable 자료구조는 `shouldComponentUpdate`의 구현에 필요한 객체의 변경사항을 추적할 수 있는 덜 자세하지만 저렴한 방법을 제공합니다. 그에 따라 immutable-js가 제공하는 추상화를 사용해 props와 state 어트리뷰트를 모델링한다면, `PureRenderMixin`을 사용해 성능을 향상할 수 있습니다. - -## Immutable-js와 Flux - -[Flux](https://facebook.github.io/flux/)를 사용한다면 immutable-js를 사용해 stores를 작성해야 합니다. [전체 API](https://facebook.github.io/immutable-js/docs/#/)를 살펴보세요. - -Immutable 자료구조를 이용해 스레드를 모델링하는 예제를 살펴봅시다. 먼저 모델링하려는 엔티티마다 `Record`를 정의해야 합니다. Record는 특정 필드들의 값을 유지하기 위한 불변의 컨테이너입니다: - -```javascript -var User = Immutable.Record({ - id: undefined, - name: undefined, - email: undefined -}); - -var Message = Immutable.Record({ - timestamp: new Date(), - sender: undefined, - text: '' -}); -``` - -`Record` 함수는 필드별로 기본값이 선언된 객체에 대한 정의를 넘겨받습니다. - -메시지 store는 두 개의 List를 통해 users와 messages를 추적할 수 있습니다: - -```javascript -this.users = Immutable.List(); -this.messages = Immutable.List(); -``` - -각각의 *페이로드* 타입을 처리하는 기능을 구현하는 것은 꽤 간단합니다. 예를 들면, store가 새 메시지를 나타내는 페이로드를 확인할 때 레코드를 새로 생성하고 메시지 리스트에 추가할 수 있습니다. - -```javascript -this.messages = this.messages.push(new Message({ - timestamp: payload.timestamp, - sender: payload.sender, - text: payload.text -}); -``` - -자료구조가 불변이기 때문에 push 함수의 결과를 `this.messages`에 할당할 필요가 있으니 주의하세요. - -React 측에서는, 컴포넌트의 state를 보존하기 위해 immutable-js 자료구조를 사용한다면, 모든 컴포넌트에 `PureRenderMixin`을 혼합해 다시 렌더링하는 프로세스를 중단할 수 있습니다. diff --git a/docs/docs/11-advanced-performance.md b/docs/docs/11-advanced-performance.md deleted file mode 100644 index 54610a7319..0000000000 --- a/docs/docs/11-advanced-performance.md +++ /dev/null @@ -1,212 +0,0 @@ ---- -id: advanced-performance -title: Advanced Performance -permalink: docs/advanced-performance.html -prev: shallow-compare.html -next: context.html ---- - -One of the first questions people ask when considering React for a project is whether their application will be as fast and responsive as an equivalent non-React version. The idea of re-rendering an entire subtree of components in response to every state change makes people wonder whether this process negatively impacts performance. React uses several clever techniques to minimize the number of costly DOM operations required to update the UI. - -## Use the production build - -If you're benchmarking or experiencing performance problems in your React apps, make sure you're testing with the [minified production build](/react/downloads.html). The development build includes extra warnings that are helpful when building your apps, but it is slower due to the extra bookkeeping it does. - -## Avoiding reconciling the DOM - -React makes use of a *virtual DOM*, which is a descriptor of a DOM subtree rendered in the browser. This parallel representation allows React to avoid creating DOM nodes and accessing existing ones, which is slower than operations on JavaScript objects. When a component's props or state change, React decides whether an actual DOM update is necessary by constructing a new virtual DOM and comparing it to the old one. Only in the case they are not equal, will React [reconcile](/react/docs/reconciliation.html) the DOM, applying as few mutations as possible. - -On top of this, React provides a component lifecycle function, `shouldComponentUpdate`, which is triggered before the re-rendering process starts (virtual DOM comparison and possible eventual DOM reconciliation), giving the developer the ability to short circuit this process. The default implementation of this function returns `true`, leaving React to perform the update: - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - return true; -} -``` - -Keep in mind that React will invoke this function pretty often, so the implementation has to be fast. - -Say you have a messaging application with several chat threads. Suppose only one of the threads has changed. If we implement `shouldComponentUpdate` on the `ChatThread` component, React can skip the rendering step for the other threads: - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - // TODO: return whether or not current chat thread is - // different to former one. -} -``` - -So, in summary, React avoids carrying out expensive DOM operations required to reconcile subtrees of the DOM by allowing the user to short circuit the process using `shouldComponentUpdate`, and, for those which should update, by comparing virtual DOMs. - -## shouldComponentUpdate in action - -Here's a subtree of components. For each one is indicated what `shouldComponentUpdate` returned and whether or not the virtual DOMs were equivalent. Finally, the circle's color indicates whether the component had to be reconciled or not. - -
                    - -In the example above, since `shouldComponentUpdate` returned `false` for the subtree rooted at C2, React had no need to generate the new virtual DOM, and therefore, it neither needed to reconcile the DOM. Note that React didn't even have to invoke `shouldComponentUpdate` on C4 and C5. - -For C1 and C3 `shouldComponentUpdate` returned `true`, so React had to go down to the leaves and check them. For C6 it returned `true`; since the virtual DOMs weren't equivalent it had to reconcile the DOM. -The last interesting case is C8. For this node React had to compute the virtual DOM, but since it was equal to the old one, it didn't have to reconcile it's DOM. - -Note that React only had to do DOM mutations for C6, which was inevitable. For C8, it bailed out by comparing the virtual DOMs, and for C2's subtree and C7, it didn't even have to compute the virtual DOM as we bailed out on `shouldComponentUpdate`. - -So, how should we implement `shouldComponentUpdate`? Say that you have a component that just renders a string value: - -```javascript -React.createClass({ - propTypes: { - value: React.PropTypes.string.isRequired - }, - - render: function() { - return
                    {this.props.value}
                    ; - } -}); -``` - -We could easily implement `shouldComponentUpdate` as follows: - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - return this.props.value !== nextProps.value; -} -``` - -So far so good, dealing with such simple props/state structures is easy. We could even generalize an implementation based on shallow equality and mix it into components. In fact, React already provides such implementation: [PureRenderMixin](/react/docs/pure-render-mixin.html). - -But what if your components' props or state are mutable data structures? Say the prop the component receives, instead of being a string like `'bar'`, is a JavaScript object that contains a string such as, `{ foo: 'bar' }`: - -```javascript -React.createClass({ - propTypes: { - value: React.PropTypes.object.isRequired - }, - - render: function() { - return
                    {this.props.value.foo}
                    ; - } -}); -``` - -The implementation of `shouldComponentUpdate` we had before wouldn't always work as expected: - -```javascript -// assume this.props.value is { foo: 'bar' } -// assume nextProps.value is { foo: 'bar' }, -// but this reference is different to this.props.value -this.props.value !== nextProps.value; // true -``` - -The problem is `shouldComponentUpdate` will return `true` when the prop actually didn't change. To fix this, we could come up with this alternative implementation: - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - return this.props.value.foo !== nextProps.value.foo; -} -``` - -Basically, we ended up doing a deep comparison to make sure we properly track changes. In terms of performance, this approach is pretty expensive. It doesn't scale as we would have to write different deep equality code for each model. On top of that, it might not even work if we don't carefully manage object references. Say this component is used by a parent: - -```javascript -React.createClass({ - getInitialState: function() { - return { value: { foo: 'bar' } }; - }, - - onClick: function() { - var value = this.state.value; - value.foo += 'bar'; // ANTI-PATTERN! - this.setState({ value: value }); - }, - - render: function() { - return ( -
                    - ); - } -}); -``` - -The first time the inner component gets rendered, it will have `{ foo: 'bar' }` as the value prop. If the user clicks on the anchor, the parent component's state will get updated to `{ value: { foo: 'barbar' } }`, triggering the re-rendering process of the inner component, which will receive `{ foo: 'barbar' }` as the new value for the prop. - -The problem is that since the parent and inner components share a reference to the same object, when the object gets mutated on line 2 of the `onClick` function, the prop the inner component had will change. So, when the re-rendering process starts, and `shouldComponentUpdate` gets invoked, `this.props.value.foo` will be equal to `nextProps.value.foo`, because in fact, `this.props.value` references the same object as `nextProps.value`. - -Consequently, since we'll miss the change on the prop and short circuit the re-rendering process, the UI won't get updated from `'bar'` to `'barbar'`. - -## Immutable-js to the rescue - -[Immutable-js](https://github.com/facebook/immutable-js) is a JavaScript collections library written by Lee Byron, which Facebook recently open-sourced. It provides *immutable persistent* collections via *structural sharing*. Let's see what these properties mean: - -* *Immutable*: once created, a collection cannot be altered at another point in time. -* *Persistent*: new collections can be created from a previous collection and a mutation such as set. The original collection is still valid after the new collection is created. -* *Structural Sharing*: new collections are created using as much of the same structure as the original collection as possible, reducing copying to a minimum to achieve space efficiency and acceptable performance. If the new collection is equal to the original, the original is often returned. - -Immutability makes tracking changes cheap; a change will always result in a new object so we only need to check if the reference to the object has changed. For example, in this regular JavaScript code: - -```javascript -var x = { foo: "bar" }; -var y = x; -y.foo = "baz"; -x === y; // true -``` - -Although `y` was edited, since it's a reference to the same object as `x`, this comparison returns `true`. However, this code could be written using immutable-js as follows: - -```javascript -var SomeRecord = Immutable.Record({ foo: null }); -var x = new SomeRecord({ foo: 'bar' }); -var y = x.set('foo', 'baz'); -x === y; // false -``` - -In this case, since a new reference is returned when mutating `x`, we can safely assume that `x` has changed. - -Another possible way to track changes could be doing dirty checking by having a flag set by setters. A problem with this approach is that it forces you to use setters and, either write a lot of additional code, or somehow instrument your classes. Alternatively, you could deep copy the object just before the mutations and deep compare to determine whether there was a change or not. A problem with this approach is both deepCopy and deepCompare are expensive operations. - -So, Immutable data structures provides you a cheap and less verbose way to track changes on objects, which is all we need to implement `shouldComponentUpdate`. Therefore, if we model props and state attributes using the abstractions provided by immutable-js we'll be able to use `PureRenderMixin` and get a nice boost in perf. - -## Immutable-js and Flux - -If you're using [Flux](https://facebook.github.io/flux/), you should start writing your stores using immutable-js. Take a look at the [full API](https://facebook.github.io/immutable-js/docs/#/). - -Let's see one possible way to model the thread example using Immutable data structures. First, we need to define a `Record` for each of the entities we're trying to model. Records are just immutable containers that hold values for a specific set of fields: - -```javascript -var User = Immutable.Record({ - id: undefined, - name: undefined, - email: undefined -}); - -var Message = Immutable.Record({ - timestamp: new Date(), - sender: undefined, - text: '' -}); -``` - -The `Record` function receives an object that defines the fields the object has and its default values. - -The messages *store* could keep track of the users and messages using two lists: - -```javascript -this.users = Immutable.List(); -this.messages = Immutable.List(); -``` - -It should be pretty straightforward to implement functions to process each *payload* type. For instance, when the store sees a payload representing a new message, we can just create a new record and append it to the messages list: - -```javascript -this.messages = this.messages.push(new Message({ - timestamp: payload.timestamp, - sender: payload.sender, - text: payload.text -}); -``` - -Note that since the data structures are immutable, we need to assign the result of the push function to `this.messages`. - -On the React side, if we also use immutable-js data structures to hold the components' state, we could mix `PureRenderMixin` into all our components and short circuit the re-rendering process. diff --git a/docs/docs/11-advanced-performance.zh-CN.md b/docs/docs/11-advanced-performance.zh-CN.md deleted file mode 100644 index 77e770522c..0000000000 --- a/docs/docs/11-advanced-performance.zh-CN.md +++ /dev/null @@ -1,212 +0,0 @@ ---- -id: advanced-performance-zh-CN -title: 提高性能 -permalink: docs/advanced-performance-zh-CN.html -prev: shallow-compare-zh-CN.html -next: context-zh-CN.html ---- - -当人们考虑将React应用到自己的系统里时,都会想知道React是否可以和非React的应用一样可以快速的响应各种用户的操作。改变组件的state时,它会重新渲染组件的所有子节点,有人会怀疑这种重新渲染会带来很大的性能开销。但是React使用很多技术来最小化的减少DOM操作的开销达到更新UI的效果。 - -## 使用生产构建版本 - -如果你在开发React应用中,遇到了一些性能上的问题,你可以使用了[minified production build](/react/downloads.html)进行测试。这个开发构建版本包括了额外的一些警告信息,可以帮助你更好的调试你的应用。由于它做了很多额外的开销,所以它运行起来会相对要慢一点。 - -## 避免调整真实DOM树 - -React利用*虚拟DOM*,来描述在浏览器上显示的真实DOM树。这种并行的表示方法,可以让React避免直接去操作DOM节点,毕竟操作DOM节点的开销要远远大于直接去操作Javascript的对象。当组件的state或者props更新的时候,React会根据新生成的虚拟DOM和之前的虚拟DOM进行比较,来判断是否需要去更新真实DOM上的内容。只有在前后虚拟DOM不相等的情况下,React才会去[调整](/react/docs/reconciliation.html)真实DOM的结构。 - -在此之上,React提供了一个组件生命周期函数`shouldComponentUpdate`,它会在组件进行重渲染过程开始的时候(虚拟DOM和真实DOM进行对比)进行调用。让开发者可以短接这个过程。该函数默认会返回`true`,让React去执行更新。 - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - return true; -} -``` - -记住一点,在React中,这个函数调用的非常频繁,所以里面的操作不能太复杂,一定要快。 - -你有几个聊天对话的消息应用程序。假设只有一个对话改变了。如果你在`ChatThread`组件中实现了`shouldComponentUpdate`函数,React可以跳过对其他线程的重渲染的步骤。 - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - // TODO: return whether or not current chat thread is - // different to former one. -} -``` - -所以,总而言之,React可以让开发者使用`shouldComponentUpdate`函数来减少对DOM子树的调整,对于那些需要更新的组件,再进行虚拟DOMs的对比。 - -## shouldComponentUpdate 实战 - -这个一个组件的子树的结构。每一个节点表示`shouldComponentUpdate` return了什么,以及是否虚拟DOMs是相等的。最后,圆的颜色代表这个节点是否需要被重新调整。 - -
                    - -在上述例子中,C2节点的`shouldComponentUpdate`函数返回了`false`,所以React就不需要在这里产生新的虚拟DOM,也就不需要重新调整DOM。由于父节点C2已经在`shouldComponentUpdate`函数中返回`false`,所以它的所有子节点也就不会执行该函数。 - -对于C1和C3,`shouldComponentUpdate`函数返回了`true`,React会从上往下对子节点进行检查。对于C6节点,它返回了`true`;由于前后的虚拟DOMs不相等,所以它不得不调整真实DOM。最后在C8这个有趣的节点上。React会去对比前后虚拟DOM,由于前后是相等的,所以它不是对真实DOM进行调整。 - -请注意,React只会对C6进行DOM操作。对于C8,它通过对比虚拟DOMs的方式,避免重新渲染。对于C2的子节点以及C7,通过`shouldComponentUpdate`函数,直接忽略了虚拟DOM比较的过程,提高性能。 - -所以,我们应该怎么样来实现`shouldComponentUpdate`方法?举个例子,你有个组件仅仅只渲染一个string的文案: - -```javascript -React.createClass({ - propTypes: { - value: React.PropTypes.string.isRequired - }, - - render: function() { - return
                    {this.props.value}
                    ; - } -}); -``` - -我们可以简单的像下面一样实现`shouldComponentUpdate` - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - return this.props.value !== nextProps.value; -} -``` - -目前为止,在props/state上处理简单的的数据结构是非常容易的。基于这种数据类型,我们可以通过mixin的方式把该函数引入到你的所有组件中去。事实上,React官方已经提供了这种方法:[PureRenderMixin](/react/docs/pure-render-mixin.html)。 - -但是,如果你的组件使用的在state或者props上使用的是可变的数据结构怎么办?组件里的prop不是以一个string的形式`'bar'`存在,而是以一种Javascript对象的形式包含了一个字符串,类似这样`{ foo: 'bar' }`: - -```javascript -React.createClass({ - propTypes: { - value: React.PropTypes.object.isRequired - }, - - render: function() { - return
                    {this.props.value.foo}
                    ; - } -}); -``` - -如果是这种情况,按照我们刚才的在`shouldComponentUpdate`的实现的话,是不能达到我们的预期: - -```javascript -// assume this.props.value is { foo: 'bar' } -// assume nextProps.value is { foo: 'bar' }, -// but this reference is different to this.props.value -this.props.value !== nextProps.value; // true -``` - -因为props实际上是没有改变的,所以`shouldComponentUpdate`始终会返回`true`。为了解决这个问题,我们也有一个可选的解决方案: - -```javascript -shouldComponentUpdate: function(nextProps, nextState) { - return this.props.value.foo !== nextProps.value.foo; -} -``` - -基本上,我们是不会利用这种深度比较去判断是否有属性改变。这样的操作十分损耗性能的,并且非常难扩展。最重要的是,如果我们没有仔细管理对象的引用关系,很可能导致对比不出结果。让我们来看看下面这个组件: - -```javascript -React.createClass({ - getInitialState: function() { - return { value: { foo: 'bar' } }; - }, - - onClick: function() { - var value = this.state.value; - value.foo += 'bar'; // ANTI-PATTERN! - this.setState({ value: value }); - }, - - render: function() { - return ( -
                    - - Click me -
                    - ); - } -}); -``` - -子组件第一次渲染的时候,组件会收到`{ foo: 'bar' }`作为prop中的value的值。如果用户进行了点击的操作,父组件为更新state,变为`{ value: { foo: 'barbar' } }`,之后会触发子组件的重渲染的过程,子组件会收到新的prop中value的值`{ foo: 'barbar' }`。 - -问题在与,因为父子组件共同分享了一个对象的引用,当这个对象在`onClick`函数中进行修改后,子组件的prop也已经改变。所以,当重渲染的过程开始,`shouldComponentUpdate`函数就会被触发,`this.props.value.foo` 与`nextProps.value.foo`会是相等的。因为`this.props.value`和`nextProps.value`指向的是同一个对象。 - -因此,我们直接阻止了子组件进行重新渲染,整个UI也就不会把`'bar'`更新为`'barbar'`。 - -## 使用Immutable-js - -[Immutable-js](https://github.com/facebook/immutable-js)是一个由Lee Byron编写的Javascript的数据类型库,现在已经被Facebook开源了。它通过 *结构共享* 的方式提供了一个 *持久不可变的* 的集合。让我们来看看这个到底是什么东西。 - -* *不可变*:一旦被创建,一个集合不能被其他内容所改变 -* *持久性*:新的集合可以由之前的集合创建出来,或者由一个可变的数据创建。当新的集合被创建出来,原始的集合依然有效。 -* *结构共享*:新的集合会尽可能的复用之前集合内的内容。减少重复复制来提高性能。如果新集合和原来的集合是相等的,则会直接把之前的集合返回给新集合。 - -不可变的特性让跟踪变化变得简单;每次改变总是会产生新的一个对象,所以。我们只需要判断一下它们引用是否相同即可。举个例子,下面是常规的Javascript的写法: - -```javascript -var x = { foo: "bar" }; -var y = x; -y.foo = "baz"; -x === y; // true -``` - -尽管`y`已经被更改了,但是它的引用还是和`x`是一致的。所以他们两个进行对比,始终会返回`true`。所以,这样的操作应该要用`immutable-js `来完成: - -```javascript -var SomeRecord = Immutable.Record({ foo: null }); -var x = new SomeRecord({ foo: 'bar' }); -var y = x.set('foo', 'baz'); -x === y; // false -``` - -在这样的情况中,当我们改变了x里的内容,会返回给我们一个新的引用,我们可以安全地假定`x`已经改变。 - -另一种来跟踪数据变化的方法,是通过 setter 来设置标识符来做脏检查 (dirty checking)。这种方法的问题在于它强迫你使用 setter;你需要多写很多额外代码或者跟踪分析 class 中的数据。另外一种方式是,你可以在更改一个对象之前对它进行一次深复制,之后再进行深比较,来判断这次操作是否造成了数据改变:这种方案的问题在于深复制与深比较都是很昂贵的操作。 - -所以,Immutable的数据结构给你提供了一个很方便的方式去跟踪一个对象是否被修改了,我们只需要简单的实现`shouldComponentUpdate`即可。因此,如果我们的props和state模型使用了immutable-js方式,我们可以引入`PureRenderMixin`,从而提高我们的应用的性能。 - -## Immutable-js 结合 Flux - -如果你正在使用[Flux](https://facebook.github.io/flux/),你应该在你的stores里使用immutable-js。可以来看下[full API](https://facebook.github.io/immutable-js/docs/#/)。 - -让我们看看一种使用Immutable数据结构来处理的方式。首先,我们为每一个入口定义一个`Record`去处理模型。`Record`是一个保存各个字段的一个容器。 - -```javascript -var User = Immutable.Record({ - id: undefined, - name: undefined, - email: undefined -}); - -var Message = Immutable.Record({ - timestamp: new Date(), - sender: undefined, - text: '' -}); -``` - -Record 函数接受一个对象作为参数;这个对象定义了 Record 中的键值与默认值 - -*store*可以用两个list来记录users和messages - - -```javascript -this.users = Immutable.List(); -this.messages = Immutable.List(); -``` - -它可以很方便的实现处理*payload*数据类型。例如,当一个store收到了新的信息,我们可以直接创建一个新的record,然后把它加到我们message的list中去。 - -```javascript -this.messages = this.messages.push(new Message({ - timestamp: payload.timestamp, - sender: payload.sender, - text: payload.text -}); -``` - -注意,因为data的数据结构是不可变的,我们需要重新对`this.message`进行赋值。 - -在React方面,如果我们用了 `immutable-js`的数据结构去保存组件的state,我们就可以引入`PureRenderMixin`到所有你的组件中,做一个快速的判断是否需要重新渲染的操作。 diff --git a/docs/docs/12-context.ko-KR.md b/docs/docs/12-context.ko-KR.md deleted file mode 100644 index 764b846279..0000000000 --- a/docs/docs/12-context.ko-KR.md +++ /dev/null @@ -1,174 +0,0 @@ ---- -id: context -title: 컨텍스트 -permalink: docs/context-ko-KR.html -prev: advanced-performance-ko-KR.html ---- - -React의 가장 큰 장점 중 하나는 React 컴포넌트를 통해 데이터의 흐름을 추적하기 쉽다는 것입니다. 컴포넌트를 보면 각각의 프로퍼티가 어떻게 전달되었는지 쉽게 파악할 수 있습니다. - -때때로 컴포넌트 트리를 통해 props을 전단하는 대신 수동으로 모든 레벨에서 데이터를 전달하고 싶은 경우가 있습니다. React의 "컨텍스트" 기능은 이를 가능하게 해줍니다. - - -> 주의: -> -> 컨텍스트는 실험적인 고급 기능입니다. 향후 릴리즈에서 API가 변경될 수 있습니다. -> -> 대부분은 애플리켄이션은 컨텍스트가 필요하지 않을겁니다. 특히 React로 시작한 경우에는 컨텍스트를 사용하지 않을겁니다. 컨텍스트의 사용은 데이터 흐름을 명확하지 않게 만들기 때문에 코드를 이해하기 어려워 집니다. 이는 마치 앱에서 전역 변수를 state로 전달하는 경우와 유사합니다. -> -> **만약 컨텍스트를 사용해야 하는 경우에도, 가능한 아껴 사용하세요.** -> -> 구축하는것이 애플리케이션이든 라이브러리든간에, 가능한 컨텍스트의 사용은 작은 영역으로 격리하고 직접적으로 컨텍스트 API를 사용하는 것을 피하세요. 그렇게 하면 API가 변경 되더라도 쉽게 업데이트 할 수 있습니다. - -## 트리를 통해 정보를 자동으로 전달하기 - -아래와 같은 구조가 있다고 가정해 봅시다: - -```javascript -var Button = React.createClass({ - render: function() { - return ( - - ); - } -}); - -var Message = React.createClass({ - render: function() { - return ( -
                    - {this.props.text} -
                    - ); - } -}); - -var MessageList = React.createClass({ - render: function() { - var color = "purple"; - var children = this.props.messages.map(function(message) { - return ; - }); - return
                    {children}
                    ; - } -}); -``` - -이 예제에서, 우리는 스타일을 주기 위해 수동으로 적절하게 `Button`과 `Messages` 컴포넌트에 `color` 프로퍼티를 엮어서 전달했습니다. 테마는 서브트리가 정보 조각의 일부(여기선 color)에 접근하기 원하는 좋은 예제입니다. 컨텍스트를 사용하면 우리는 이를 자동으로 트리로 전달할 수 있습니다: - -```javascript{2-4,7,18,25-30,33} -var Button = React.createClass({ - contextTypes: { - color: React.PropTypes.string - }, - render: function() { - return ( - - ); - } -}); - -var Message = React.createClass({ - render: function() { - return ( -
                    - {this.props.text} -
                    - ); - } -}); - -var MessageList = React.createClass({ - childContextTypes: { - color: React.PropTypes.string - }, - getChildContext: function() { - return {color: "purple"}; - }, - render: function() { - var children = this.props.messages.map(function(message) { - return ; - }); - return
                    {children}
                    ; - } -}); -``` - -`childContextTypes`와 `getChildContext`를 `MessageList`(context provider)에 추가함으로써, React는 정보를 자동으로 아래로 전달하며 서브트리내의 어떤 컴포넌트든 (여기선 `Button`) `contextTypes`를 정의함으로써 이에 접근할 수 있습니다. - -`contextTypes`가 정의되지 않은 경우, `this.context`는 빈 오브젝트가 됩니다. - -## 부모-자식 커플링 - -컨텍스트는 다음과 같은 API를 구성할 수 있게 해줍니다: - -```javascript - - 가지 - 땅콩호박 - 클레멘타인 - -``` - -`Menu` 컴포넌트에서 관련 정보를 전달함으로써 각각의 `MenuItem`가 부모인 `Menu` 컴포넌트와 통신할 수 있습니다. - -**이 API를 이용해 컴포넌트를 구성하기 전에, 깔끔한 대안이 있는지 먼저 고려해 보세요.** 다음과 같이 간단히 아이템을 배열로 넘겨 보겠습니다: - -```javascript - -``` - -원한다면 전체 React 컴포넌트를 프로퍼티로 전달할 수도 있습니다. - -## Referencing context in lifecycle methods - -If `contextTypes` is defined within a component, the following lifecycle methods will receive an additional parameter, the `context` object: - -```javascript -void componentWillReceiveProps( - object nextProps, object nextContext -) - -boolean shouldComponentUpdate( - object nextProps, object nextState, object nextContext -) - -void componentWillUpdate( - object nextProps, object nextState, object nextContext -) - -void componentDidUpdate( - object prevProps, object prevState, object prevContext -) -``` - -## Referencing context in stateless functional components - -Stateless functional components are also able to reference `context` if `contextTypes` is defined as a property of the function. The following code shows the `Button` component above written as a stateless functional component. - -```javascript -function Button(props, context) { - return ( - - ); -} -Button.contextTypes = {color: React.PropTypes.string}; -``` - -## 컨텍스트를 사용하지 말아야 하는 경우 - -대부분의 경우, 깔끔한 코드를 위해 전역 변수를 피하는 것과 마찬가지로 컨텍스트의 사용을 피해야 합니다. 특히 "타이핑을 줄이거나" 명시적인 프로퍼티 전달 대신 이를 사용하려는 경우 다시 한번 생각해 보세요. - -컨텍스트의 가장 적절한 사용 사례는 로그인한 유저, 언어 설정, 테마 정보 등을 암시적으로 전달하는 것입니다. 컨텍스트를 사용함으로써 이런 정보들을 전역으로 다루는 대신 단일 React 서브트리 내에서 다룰 수 있습니다. - -모델 데이터를 컴포넌트로 전달하는데 컨텍스트를 사용하지 마세요. 트리를 통해 명시적으로 데이터를 엮어 전달하는 것이 훨씬 이해하기 쉽습니다. 컨텍스트는 렌더되는 위치에 따라 다르게 작동하기 때문에 컴포넌트를 더욱 연결되고(coupled) 재사용성이 떨어지게 만듭니다. - -## 알려진 한계점 - -컴포넌트에 의해 제공되는 컨텍스트의 값이 변경될 때, 중간 부모가 `shouldComponentUpdate`에서`false`을 반환한다면 그 값을 사용하는 자손은 업데이트되지 않습니다. 자세한 내용은 [#2517](https://github.com/facebook/react/issues/2517) 이슈를 확인하세요. diff --git a/docs/docs/12-context.zh-CN.md b/docs/docs/12-context.zh-CN.md deleted file mode 100644 index 5b114d45fe..0000000000 --- a/docs/docs/12-context.zh-CN.md +++ /dev/null @@ -1,205 +0,0 @@ ---- -id: context-zh-CN -title: Context -permalink: docs/context-zh-CN.html -prev: advanced-performance-zh-CN.html ---- - -React优势之一是你可以很容易地从React组件里跟踪数据流动。当你查看一个组件时,你可以很容易地判断出传入了哪些props,而这也有利于你的App进行逻辑推断。 - -有时,你想不通过在每一级组件设置prop的方式来向组件树内传递数据。那么,React的"context"特性可以让你做到这点。 - -> 注意: -> -> Context是一个先进的实验性特性,这个API很可能在未来版本变化。 -> -> 大多数应用将不会需要用到context。尤其是如果你刚开始用React,你很可能不会想用它。使用context将会使你的代码难以理解,因为它让数据流变得不清晰。它类似于在你的应用里用以传递state的全局变量。 -> -> **如果你必须使用context,请保守地使用它。** -> -> 不论你正在创建一个应用或者是库,试着缩小context的使用范围,并尽可能避免直接使用context相关API,以便在API变动时容易升级。 - -## 在组件树内自动传递info - -假设你有一个这样的结构: - -```javascript -var Button = React.createClass({ - render: function() { - return ( - - ); - } -}); - -var Message = React.createClass({ - render: function() { - return ( -
                    - {this.props.text} -
                    - ); - } -}); - -var MessageList = React.createClass({ - render: function() { - var color = "purple"; - var children = this.props.messages.map(function(message) { - return ; - }); - return
                    {children}
                    ; - } -}); -``` - -在这个例子里,我们手工传递一个叫`color`的prop,以便于给`Button`和`Message`组件添加合适的样式。当你想所有子组件可以访问一部分信息时(比如color),上面的设置主题是一个很好的例子。通过使用context,我们能自动在组件树中传递信息: - -```javascript{2-4,7,18,25-30,33} -var Button = React.createClass({ - contextTypes: { - color: React.PropTypes.string - }, - render: function() { - return ( - - ); - } -}); - -var Message = React.createClass({ - render: function() { - return ( -
                    - {this.props.text} -
                    - ); - } -}); - -var MessageList = React.createClass({ - childContextTypes: { - color: React.PropTypes.string - }, - getChildContext: function() { - return {color: "purple"}; - }, - render: function() { - var children = this.props.messages.map(function(message) { - return ; - }); - return
                    {children}
                    ; - } -}); -``` - -通过添加`childContextTypes`和`getChildContext`到 `MessageList`(context提供者),React会自动下传信息,并且通过定义`contextTypes`,子树中的任何组件(在这个例子中,子组件是`Button`)可以访问`context`。 - -如果`contextTypes`没有定义,那么`this.context`将是一个空对象。 - -## 父子耦合 - -Context同样可以使你构建这样的API: - -```javascript - - aubergine - butternut squash - clementine - -``` - -通过在`Menu`组件内下传相关的信息,每个`MenuItem` 可以与包含他们的`Menu`组件沟通。 - -**在你用这个API构建组件以前,考虑一下是否有清晰的替代方案** 我们喜欢用数组传递items,就像下面这样: - -```javascript - -``` - -记住,如果你愿意,你同样可以在props里传递整个React组件。 - -## 在生命周期方法里引用context - -如果`contextTypes`是定义在一个组件中,接下来的生命周期方法会收到一个额外的参数,`context`对象: - -```javascript -void componentWillReceiveProps( - object nextProps, object nextContext -) - -boolean shouldComponentUpdate( - object nextProps, object nextState, object nextContext -) - -void componentWillUpdate( - object nextProps, object nextState, object nextContext -) - -void componentDidUpdate( - object prevProps, object prevState, object prevContext -) -``` - -## 在无状态函数组件里引用 context - -如果 `contextTypes` 被定义为函数的属性,无状态函数同样能够引用`context`。下面的代码展示了被写为无状态函数组件的`Button`组件: - -```javascript -function Button(props, context) { - return ( - - ); -} -Button.contextTypes = {color: React.PropTypes.string}; -``` - -## 更新context - -当state或props改变时,会调用`getChildContext`方法。为了能更新context内的数据,需要使用`this.setState`来触发组件state更新。这将会触发一个新的context,并且子组件也能接收变化。 - -```javascript -var MediaQuery = React.createClass({ - getInitialState: function(){ - return {type:'desktop'}; - }, - childContextTypes: { - type: React.PropTypes.string - }, - getChildContext: function() { - return {type: this.state.type}; - }, - componentDidMount: function(){ - var checkMediaQuery = function(){ - var type = window.matchMedia("(min-width: 1025px)").matches ? 'desktop' : 'mobile'; - if (type !== this.state.type){ - this.setState({type:type}); - } - }; - - window.addEventListener('resize', checkMediaQuery); - checkMediaQuery(); - }, - render: function(){ - return this.props.children; - } -}); -``` - -## 什么时候不用 context - -正如在写清晰代码时最好要避免使用全局变量一样,在大多数情况下,你应该避免使用context。特别是,在用它来"节省输入"和代替显式传入props时要三思。 - -隐式传入登录的用户,当前的语言,或者主题信息,是context最好的使用场景。要不然所有这些可能就是全局变量,但是context让你限定他们到一个单独的React树里。 - -在组件里传递你的模型数据时,不要依赖context。在组件树内显式传递数据,会更容易令人理解。之所以使用context会增加组件耦合度以及降低复用性,是因为组件在不同的地方渲染时,他们会表现出不同的行为。 - -## 已知的限制 - -假设由父组件提供的context值发生变动,但中间父级组件的`shouldComponentUpdate`返回了`false`,那么后代子级不会更新context。详见 issue [#2517](https://github.com/facebook/react/issues/2517) 。 diff --git a/docs/docs/10.1-animation.md b/docs/docs/addons-animation.md similarity index 71% rename from docs/docs/10.1-animation.md rename to docs/docs/addons-animation.md index fcd2808041..b9d0c60fe1 100644 --- a/docs/docs/10.1-animation.md +++ b/docs/docs/addons-animation.md @@ -1,24 +1,28 @@ --- id: animation -title: Animation +title: Animation Add-Ons permalink: docs/animation.html +layout: docs +category: Add-Ons prev: addons.html -next: two-way-binding-helpers.html +next: create-fragment.html --- -React provides a `ReactTransitionGroup` add-on component as a low-level API for animation, and a `ReactCSSTransitionGroup` for easily implementing basic CSS animations and transitions. +The [`ReactTransitionGroup`](#reacttransitiongroup) add-on component is a low-level API for animation, and [`ReactCSSTransitionGroup`](#reactcsstransitiongroup) is an add-on component for easily implementing basic CSS animations and transitions. -## High-level API: `ReactCSSTransitionGroup` +## High-level API: ReactCSSTransitionGroup -`ReactCSSTransitionGroup` is based on `ReactTransitionGroup` and is an easy way to perform CSS transitions and animations when a React component enters or leaves the DOM. It's inspired by the excellent [ng-animate](http://www.nganimate.org/) library. +`ReactCSSTransitionGroup` is a high-level API based on [`ReactTransitionGroup`](#low-level-api-reacttransitiongroup) and is an easy way to perform CSS transitions and animations when a React component enters or leaves the DOM. It's inspired by the excellent [ng-animate](http://www.nganimate.org/) library. -### Getting Started +**Importing** -`ReactCSSTransitionGroup` is the interface to `ReactTransitions`. This is a simple element that wraps all of the components you are interested in animating. Here's an example where we fade list items in and out. - -```javascript{33-38} -var ReactCSSTransitionGroup = require('react-addons-css-transition-group'); +```javascript +import ReactCSSTransitionGroup from 'react-addons-css-transition-group' // ES6 +var ReactCSSTransitionGroup = require('react-addons-css-transition-group') // ES5 with npm +var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup; // ES5 with react-with-addons.js +``` +```javascript{31-36} class TodoList extends React.Component { constructor(props) { super(props); @@ -49,9 +53,9 @@ class TodoList extends React.Component { return (
                    - {items} @@ -96,16 +100,16 @@ You'll notice that animation durations need to be specified in both the CSS and `ReactCSSTransitionGroup` provides the optional prop `transitionAppear`, to add an extra transition phase at the initial mount of the component. There is generally no transition phase at the initial mount as the default value of `transitionAppear` is `false`. The following is an example which passes the prop `transitionAppear` with the value `true`. ```javascript{5-6} - render() { - return ( - -

                    Fading at Initial Mount

                    -
                    - ); - } +render() { + return ( + +

                    Fading at Initial Mount

                    +
                    + ); +} ``` During the initial mount `ReactCSSTransitionGroup` will get the `example-appear` CSS class and the `example-appear-active` CSS class added in the next tick. @@ -132,28 +136,28 @@ At the initial mount, all children of the `ReactCSSTransitionGroup` will `appear It is also possible to use custom class names for each of the steps in your transitions. Instead of passing a string into transitionName you can pass an object containing either the `enter` and `leave` class names, or an object containing the `enter`, `enter-active`, `leave-active`, and `leave` class names. If only the enter and leave classes are provided, the enter-active and leave-active classes will be determined by appending '-active' to the end of the class name. Here are two examples using custom classes: ```javascript - ... - - {item} - +// ... + + {item} + - - {item2} - - ... + + {item2} + +// ... ``` ### Animation Group Must Be Mounted To Work @@ -163,22 +167,22 @@ In order for it to apply transitions to its children, the `ReactCSSTransitionGro The example below would **not** work, because the `ReactCSSTransitionGroup` is being mounted along with the new item, instead of the new item being mounted within it. Compare this to the [Getting Started](#getting-started) section above to see the difference. ```javascript{4,6,13} - render() { - var items = this.state.items.map((item, i) => ( -
                    this.handleRemove(i)}> - - {item} - -
                    - )); +render() { + var items = this.state.items.map((item, i) => ( +
                    this.handleRemove(i)}> + + {item} + +
                    + )); - return ( -
                    - - {items} -
                    - ); - } + return ( +
                    + + {items} +
                    + ); +} ``` ### Animating One or Zero Items @@ -186,7 +190,7 @@ The example below would **not** work, because the `ReactCSSTransitionGroup` is b In the example above, we rendered a list of items into `ReactCSSTransitionGroup`. However, the children of `ReactCSSTransitionGroup` can also be one or zero items. This makes it possible to animate a single element entering or leaving. Similarly, you can animate a new element replacing the current element. For example, we can implement a simple image carousel like this: ```javascript{10} -var ReactCSSTransitionGroup = require('react-addons-css-transition-group'); +import ReactCSSTransitionGroup from 'react-addons-css-transition-group'; function ImageCarousel(props) { return ( @@ -210,41 +214,34 @@ You can disable animating `enter` or `leave` animations if you want. For example > > When using `ReactCSSTransitionGroup`, there's no way for your components to be notified when a transition has ended or to perform any more complex logic around animation. If you want more fine-grained control, you can use the lower-level `ReactTransitionGroup` API which provides the hooks you need to do custom transitions. -## Low-level API: `ReactTransitionGroup` +* * * -`ReactTransitionGroup` is the basis for animations. It is accessible from `require('react-addons-transition-group')`. When children are declaratively added or removed from it (as in the example above) special lifecycle hooks are called on them. +## Low-level API: ReactTransitionGroup -### `componentWillAppear(callback)` +**Importing** -This is called at the same time as `componentDidMount()` for components that are initially mounted in a `TransitionGroup`. It will block other animations from occurring until `callback` is called. It is only called on the initial render of a `TransitionGroup`. +```javascript +import ReactTransitionGroup from 'react-addons-transition-group' // ES6 +var ReactTransitionGroup = require('react-addons-transition-group') // ES5 with npm +var ReactTransitionGroup = React.addons.TransitionGroup; // ES5 with react-with-addons.js +``` -### `componentDidAppear()` +`ReactTransitionGroup` is the basis for animations. When children are declaratively added or removed from it (as in the [example above](#getting-started)), special lifecycle hooks are called on them. -This is called after the `callback` function that was passed to `componentWillAppear` is called. + - [`componentWillAppear()`](#componentwillappear) + - [`componentDidAppear()`](#componentdidappear) + - [`componentWillEnter()`](#componentwillenter) + - [`componentDidEnter()`](#componentdidenter) + - [`componentWillLeave()`](#componentwillleave) + - [`componentDidLeave()`](#componentdidleave) -### `componentWillEnter(callback)` +#### Rendering a Different Component -This is called at the same time as `componentDidMount()` for components added to an existing `TransitionGroup`. It will block other animations from occurring until `callback` is called. It will not be called on the initial render of a `TransitionGroup`. - -### `componentDidEnter()` - -This is called after the `callback` function that was passed to `componentWillEnter` is called. - -### `componentWillLeave(callback)` - -This is called when the child has been removed from the `ReactTransitionGroup`. Though the child has been removed, `ReactTransitionGroup` will keep it in the DOM until `callback` is called. - -### `componentDidLeave()` - -This is called when the `willLeave` `callback` is called (at the same time as `componentWillUnmount`). - -### Rendering a Different Component - -By default `ReactTransitionGroup` renders as a `span`. You can change this behavior by providing a `component` prop. For example, here's how you would render a `
                      `: +`ReactTransitionGroup` renders as a `span` by default. You can change this behavior by providing a `component` prop. For example, here's how you would render a `
                        `: ```javascript{1} - ... + {/* ... */} ``` @@ -252,13 +249,13 @@ Any additional, user-defined, properties will become properties of the rendered ```javascript{1} - ... + {/* ... */} ``` Every DOM component that React can render is available for use. However, `component` does not need to be a DOM component. It can be any React component you want; even ones you've written yourself! Just write `component={List}` and your component will receive `this.props.children`. -### Rendering a Single Child +#### Rendering a Single Child People often use `ReactTransitionGroup` to animate mounting and unmounting of a single child such as a collapsible panel. Normally `ReactTransitionGroup` wraps all its children in a `span` (or a custom `component` as described above). This is because any React component has to return a single root element, and `ReactTransitionGroup` is no exception to this rule. @@ -280,3 +277,65 @@ Now you can specify `FirstChild` as the `component` prop in `` needs to give them a common DOM parent. You can't avoid the wrapper for multiple children, but you can customize the wrapper with the `component` prop as described above. + +* * * + +## Reference + +### `componentWillAppear()` + +```javascript +componentWillAppear(callback) +``` + +This is called at the same time as `componentDidMount()` for components that are initially mounted in a `TransitionGroup`. It will block other animations from occurring until `callback` is called. It is only called on the initial render of a `TransitionGroup`. + +* * * + +### `componentDidAppear()` + +```javascript +componentDidAppear() +``` + +This is called after the `callback` function that was passed to `componentWillAppear` is called. + +* * * + +### `componentWillEnter()` + +```javascript +componentWillEnter(callback) +``` + +This is called at the same time as `componentDidMount()` for components added to an existing `TransitionGroup`. It will block other animations from occurring until `callback` is called. It will not be called on the initial render of a `TransitionGroup`. + +* * * + +### `componentDidEnter()` + +```javascript +componentDidEnter() +``` + +This is called after the `callback` function that was passed to [`componentWillEnter()`](#componentwillenter) is called. + +* * * + +### `componentWillLeave()` + +```javascript +componentWillLeave(callback) +``` + +This is called when the child has been removed from the `ReactTransitionGroup`. Though the child has been removed, `ReactTransitionGroup` will keep it in the DOM until `callback` is called. + +* * * + +### `componentDidLeave()` + +```javascript +componentDidLeave() +``` + +This is called when the `willLeave` `callback` is called (at the same time as `componentWillUnmount()`). diff --git a/docs/docs/10.6-create-fragment.md b/docs/docs/addons-create-fragment.md similarity index 71% rename from docs/docs/10.6-create-fragment.md rename to docs/docs/addons-create-fragment.md index 47a13506f6..a9e841ff52 100644 --- a/docs/docs/10.6-create-fragment.md +++ b/docs/docs/addons-create-fragment.md @@ -2,10 +2,22 @@ id: create-fragment title: Keyed Fragments permalink: docs/create-fragment.html -prev: clone-with-props.html -next: update.html +layout: docs +category: Add-Ons +prev: animation.html +next: perf.html --- +**Importing** + +```javascript +import createFragment from 'react-addons-create-fragment' // ES6 +var createFragment = require('react-addons-create-fragment') // ES5 with npm +var createFragment = React.addons.createFragment; // ES5 with react-with-addons.js +``` + +## Overview + In most cases, you can use the `key` prop to specify keys on the elements you're returning from `render`. However, this breaks down in one situation: if you have two sets of children that you need to reorder, there's no way to put a key on each set without adding a wrapper element. That is, if you have a component such as: @@ -52,4 +64,4 @@ function Swapper(props) { The keys of the passed object (that is, `left` and `right`) are used as keys for the entire set of children, and the order of the object's keys is used to determine the order of the rendered children. With this change, the two sets of children will be properly reordered in the DOM without unmounting. -The return value of `createFragment` should be treated as an opaque object; you can use the `React.Children` helpers to loop through a fragment but should not access it directly. Note also that we're relying on the JavaScript engine preserving object enumeration order here, which is not guaranteed by the spec but is implemented by all major browsers and VMs for objects with non-numeric keys. +The return value of `createFragment` should be treated as an opaque object; you can use the [`React.Children`](/react/docs/react-api.html#react.children) helpers to loop through a fragment but should not access it directly. Note also that we're relying on the JavaScript engine preserving object enumeration order here, which is not guaranteed by the spec but is implemented by all major browsers and VMs for objects with non-numeric keys. diff --git a/docs/docs/addons-perf.md b/docs/docs/addons-perf.md new file mode 100644 index 0000000000..845e20bf9a --- /dev/null +++ b/docs/docs/addons-perf.md @@ -0,0 +1,146 @@ +--- +id: perf +title: Performance Tools +permalink: docs/perf.html +layout: docs +category: Add-Ons +prev: create-fragment.html +next: test-utils.html +--- + +**Importing** + +```javascript +import Perf from 'react-addons-perf' // ES6 +var Perf = require('react-addons-perf') // ES5 with npm +var Perf = React.addons.Perf; // ES5 with react-with-addons.js +``` + + +## Overview + +React is usually quite fast out of the box. However, in situations where you need to squeeze every ounce of performance out of your app, it provides a [shouldComponentUpdate()](/react/docs/react-component.html#shouldcomponentupdate) hook where you can add optimization hints to React's diff algorithm. + +In addition to giving you an overview of your app's overall performance, `Perf` is a profiling tool that tells you exactly where you need to put these hooks. + +See these articles by the [Benchling Engineering Team](http://benchling.engineering) for a in-depth introduction to performance tooling: + + - ["Performance Engineering with React"](http://benchling.engineering/performance-engineering-with-react/) + - ["A Deep Dive into React Perf Debugging"](http://benchling.engineering/deep-dive-react-perf-debugging/) + +### Development vs. Production Builds + +If you're benchmarking or seeing performance problems in your React apps, make sure you're testing with the [minified production build](/react/downloads.html). The development build includes extra warnings that are helpful when building your apps, but it is slower due to the extra bookkeeping it does. + +However, the perf tools described on this page only work when using the development build of React. Therefore, the profiler only serves to indicate the _relatively_ expensive parts of your app. + +### Using Perf + +The `Perf` object can be used with React in development mode only. You should not include this bundle when building your app for production. + +#### Getting Measurements + + - [`start()`](#start) + - [`stop()`](#stop) + - [`getLastMeasurements()`](#getlastmeasurements) + +#### Printing Results + +The following methods use the measurements returned by [`Perf.getLastMeasurements()`](#getlastmeasurements) to pretty-print the result. + + - [`printInclusive()`](#printinclusive) + - [`printExclusive()`](#printexclusive) + - [`printWasted()`](#printwasted) + - [`printOperations()`](#printoperations) + - [`printDOM()`](#printdom) + +* * * + +## Reference + +### `start()` +### `stop()` + +```javascript +Perf.start() +// ... +Perf.stop() +``` + +Start/stop the measurement. The React operations in-between are recorded for analyses below. Operations that took an insignificant amount of time are ignored. + +After stopping, you will need [`Perf.getLastMeasurements()`](#getlastmeasurements) to get the measurements. + +* * * + +### `getLastMeasurements()` + +```javascript +Perf.getLastMeasurements() +``` + +Get the opaque data structure describing measurements from the last start-stop session. You can save it and pass it to the other print methods in [`Perf`](#printing-results) to analyze past measurements. + +> Note +> +> Don't rely on the exact format of the return value because it may change in minor releases. We will update the documentation if the return value format becomes a supported part of the public API. + +* * * + +### `printInclusive()` + +```javascript +Perf.printInclusive(measurements) +``` + +Prints the overall time taken. If no argument's passed, defaults to all the measurements from the last recording. This prints a nicely formatted table in the console, like so: + +![](/react/img/docs/perf-inclusive.png) + +* * * + +### `printExclusive()` + +```javascript +Perf.printExclusive(measurements) +``` + +"Exclusive" times don't include the times taken to mount the components: processing props, calling `componentWillMount` and `componentDidMount`, etc. + +![](/react/img/docs/perf-exclusive.png) + +* * * + +### `printWasted()` + +```javascript +Perf.printWasted(measurements) +``` + +**The most useful part of the profiler**. + +"Wasted" time is spent on components that didn't actually render anything, e.g. the render stayed the same, so the DOM wasn't touched. + +![](/react/img/docs/perf-wasted.png) + +* * * + +### `printOperations()` + +```javascript +Perf.printOperations(measurements) +``` + +Prints the underlying DOM manipulations, e.g. "set innerHTML" and "remove". + +![](/react/img/docs/perf-dom.png) + +* * * + +### `printDOM()` + +```javascript +Perf.printDOM(measurements) +``` + +This method has been renamed to [`printOperations()`](#printoperations). Currently `printDOM()` still exists as an alias but it prints a deprecation warning and will eventually be removed. diff --git a/docs/docs/addons-pure-render-mixin.md b/docs/docs/addons-pure-render-mixin.md new file mode 100644 index 0000000000..4d741e91b1 --- /dev/null +++ b/docs/docs/addons-pure-render-mixin.md @@ -0,0 +1,42 @@ +--- +id: pure-render-mixin +title: PureRenderMixin +permalink: docs/pure-render-mixin.html +layout: docs +category: Add-Ons +--- + +> Note: +> `PureRenderMixin` is a legacy add-on. Use [`React.PureComponent`](/react/docs/react-api.html#react.purecomponent) instead. + +**Importing** + +```javascript +import PureRenderMixin from 'react-addons-pure-render-mixin' // ES6 +var PureRenderMixin = require('react-addons-pure-render-mixin') // ES5 with npm +var PureRenderMixin = React.addons.PureRenderMixin; // ES5 with react-with-addons.js +``` + +## Overview + +If your React component's render function renders the same result given the same props and state, you can use this mixin for a performance boost in some cases. + +Example: + +```js +React.createClass({ + mixins: [PureRenderMixin], + + render: function() { + return
                        foo
                        ; + } +}); +``` + +Under the hood, the mixin implements [shouldComponentUpdate](/react/docs/component-specs.html#updating-shouldcomponentupdate), in which it compares the current props and state with the next ones and returns `false` if the equalities pass. + +> Note: +> +> This only shallowly compares the objects. If these contain complex data structures, it may produce false-negatives for deeper differences. Only mix into components which have simple props and state, or use `forceUpdate()` when you know deep data structures have changed. Or, consider using [immutable objects](https://facebook.github.io/immutable-js/) to facilitate fast comparisons of nested data. +> +> Furthermore, `shouldComponentUpdate` skips updates for the whole component subtree. Make sure all the children components are also "pure". diff --git a/docs/docs/10.10-shallow-compare.md b/docs/docs/addons-shallow-compare.md similarity index 62% rename from docs/docs/10.10-shallow-compare.md rename to docs/docs/addons-shallow-compare.md index 39042092ea..f123931d2c 100644 --- a/docs/docs/10.10-shallow-compare.md +++ b/docs/docs/addons-shallow-compare.md @@ -2,18 +2,30 @@ id: shallow-compare title: Shallow Compare permalink: docs/shallow-compare.html -prev: perf.html -next: advanced-performance.html +layout: docs +category: Reference --- -`shallowCompare` is a helper function to achieve the same functionality as `PureRenderMixin` while using ES6 classes with React. +> Note: +> `shallowCompare` is a legacy add-on. Use [`React.PureComponent`](/react/docs/react-api.html#react.purecomponent) instead. + +**Importing** + +```javascript +import shallowCompare from 'react-addons-shallow-compare' // ES6 +var shallowCompare = require('react-addons-shallow-compare') // ES5 with npm +var shallowCompare = React.addons.shallowCompare; // ES5 with react-with-addons.js +``` + +## Overview + +Before [`React.PureComponent`](/react/docs/react-api.html#react.purecomponent) was introduced, `shallowCompare` was commonly used to achieve the same functionality as [`PureRenderMixin`](pure-render-mixin.html) while using ES6 classes with React. If your React component's render function is "pure" (in other words, it renders the same result given the same props and state), you can use this helper function for a performance boost in some cases. Example: ```js -var shallowCompare = require('react-addons-shallow-compare'); export class SampleComponent extends React.Component { shouldComponentUpdate(nextProps, nextState) { return shallowCompare(this, nextProps, nextState); diff --git a/docs/docs/addons-test-utils.md b/docs/docs/addons-test-utils.md new file mode 100644 index 0000000000..19f07900ed --- /dev/null +++ b/docs/docs/addons-test-utils.md @@ -0,0 +1,326 @@ +--- +id: test-utils +title: Test Utilities +permalink: docs/test-utils.html +layout: docs +category: Reference +prev: perf.html +--- + +**Importing** + +```javascript +import ReactTestUtils from 'react-addons-test-utils' // ES6 +var ReactTestUtils = require('react-addons-test-utils') // ES5 with npm +var ReactTestUtils = React.addons.TestUtils; // ES5 with react-with-addons.js +``` + +## Overview + +`ReactTestUtils` makes it easy to test React components in the testing framework of your choice. At Facebook we use [Jest](https://facebook.github.io/jest/) for painless JavaScript testing. Learn how to get started with Jest through the Jest website's [React Tutorial](http://facebook.github.io/jest/docs/tutorial-react.html#content). + +> Note: +> +> Airbnb has released a testing utility called Enzyme, which makes it easy to assert, manipulate, and traverse your React Components' output. If you're deciding on a unit testing utility to use together with Jest, or any other test runner, it's worth checking out: [http://airbnb.io/enzyme/](http://airbnb.io/enzyme/) + + - [`Simulate`](#simulate) + - [`renderIntoDocument()`](#renderintodocument) + - [`mockComponent()`](#mockcomponent) + - [`isElement()`](#iselement) + - [`isElementOfType()`](#iselementoftype) + - [`isDOMComponent()`](#isdomcomponent) + - [`isCompositeComponent()`](#iscompositecomponent) + - [`isCompositeComponentWithType()`](#iscompositecomponentwithtype) + - [`findAllInRenderedTree()`](#findallinrenderedtree) + - [`scryRenderedDOMComponentsWithClass()`](#scryrendereddomcomponentswithclass) + - [`findRenderedDOMComponentWithClass()`](#findrendereddomcomponentwithclass) + - [`scryRenderedDOMComponentsWithTag()`](#scryrendereddomcomponentswithtag) + - [`findRenderedDOMComponentWithTag()`](#findrendereddomcomponentwithtag) + - [`scryRenderedComponentsWithType()`](#scryrenderedcomponentswithtype) + - [`findRenderedComponentWithType()`](#findrenderedcomponentwithtype) + +### Shallow Rendering + +Shallow rendering lets you render a component "one level deep" and assert facts about what its render method returns, without worrying about the behavior of child components, which are not instantiated or rendered. This does not require a DOM. + + - [`createRenderer()`](#createrenderer) + - [`shallowRenderer.render()`](#shallowrenderer.render) + - [`shallowRenderer.getRenderOutput()`](#shallowrenderer.getrenderoutput) + +Call [`createRenderer()`](#createrenderer) in your tests to create a shallow renderer. You can think of this as a "place" to render the component you're testing, and from which you can extract the component's output. + +[`shadowRenderer.render()`](#shallowrenderer.render) is similar to [`ReactDOM.render()`](/react/docs/react-dom.html#render) but it doesn't require DOM and only renders a single level deep. This means you can test components in isolated from how their children are implemented. + +After `shadowRenderer.render()` has been called, you can use [`shallowRenderer.getRenderOutput()`](#shallowrenderer.getrenderoutput) to get the shallowly rendered output. + +You can then begin to assert facts about the output. For example, if your component's render method returns: + +```javascript +
                        + Title + +
                        +``` + +Then you can assert: + +```javascript +var renderer = ReactTestUtils.createRenderer(); +result = renderer.getRenderOutput(); +expect(result.type).toBe('div'); +expect(result.props.children).toEqual([ + Title, + +]); +``` + +Shallow testing currently has some limitations, namely not supporting refs. + +We also recommend checking out Enzyme's [Shallow Rendering API](http://airbnb.io/enzyme/docs/api/shallow.html). It provides a nicer higher-level API over the same functionality. + +* * * + +## Reference + +### `Simulate` + +```javascript +Simulate.{eventName}( + element, + [eventData] +) +``` + +Simulate an event dispatch on a DOM node with optional `eventData` event data. + +`Simulate` has a method for [every event that React understands](/react/docs/events.html#supported-events). + +**Clicking an element** + +```javascript +// +var node = this.refs.button; +ReactTestUtils.Simulate.click(node); +``` + +**Changing the value of an input field and then pressing ENTER.** + +```javascript +// +var node = this.refs.input; +node.value = 'giraffe'; +ReactTestUtils.Simulate.change(node); +ReactTestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13}); +``` + +> Note +> +> You will have to provide any event property that you're using in your component (e.g. keyCode, which, etc...) as React is not creating any of these for you. + +* * * + +### `renderIntoDocument()` + +```javascript +renderIntoDocument(instance) +``` + +Render a component into a detached DOM node in the document. **This function requires a DOM.** + +> Note: +> +> You will need to have `window`, `window.document` and `window.document.createElement` globally available **before** you import `React`. Otherwise React will think it can't access the DOM and methods like `setState` won't work. + +* * * + +### `mockComponent()` + +```javascript +mockComponent( + componentClass, + [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 `
                        ` (or other tag if `mockTagName` is provided) containing any provided children. + +* * * + +### `isElement()` + +```javascript +isElement(element) +``` + +Returns `true` if `element` is any React element. + +* * * + +### `isElementOfType()` + +```javascript +isElementOfType( + element, + componentClass +) +``` + +Returns `true` if `element` is a React element whose type is of a React `componentClass`. + +* * * + +### `isDOMComponent()` + +```javascript +isDOMComponent(instance) +``` + +Returns `true` if `instance` is a DOM component (such as a `
                        ` or ``). + +* * * + +### `isCompositeComponent()` + +```javascript +isCompositeComponent(instance) +``` + +Returns `true` if `instance` is a user-defined component, such as a class or a function. + +* * * + +### `isCompositeComponentWithType()` + +```javascript +isCompositeComponentWithType( + instance, + componentClass +) +``` + +Returns `true` if `instance` is a component whose type is of a React `componentClass`. + +* * * + +### `findAllInRenderedTree()` + +```javascript +findAllInRenderedTree( + tree, + test +) +``` + +Traverse all components in `tree` and accumulate all components where `test(component)` is `true`. This is not that useful on its own, but it's used as a primitive for other test utils. + +* * * + +### `scryRenderedDOMComponentsWithClass()` + +```javascript +scryRenderedDOMComponentsWithClass( + tree, + className +) +``` + +Finds all DOM elements of components in the rendered tree that are DOM components with the class name matching `className`. + +* * * + +### `findRenderedDOMComponentWithClass()` + +```javascript +findRenderedDOMComponentWithClass( + tree, + className +) +``` + +Like [`scryRenderedDOMComponentsWithClass()`](#scryrendereddomcomponentswithclass) but expects there to be one result, and returns that one result, or throws exception if there is any other number of matches besides one. + +* * * + +### `scryRenderedDOMComponentsWithTag()` + +```javascript +scryRenderedDOMComponentsWithTag( + tree, + tagName +) +``` + +Finds all DOM elements of components in the rendered tree that are DOM components with the tag name matching `tagName`. + +* * * + +### `findRenderedDOMComponentWithTag()` + +```javascript +findRenderedDOMComponentWithTag( + tree, + tagName +) +``` + +Like [`scryRenderedDOMComponentsWithTag()`](#scryrendereddomcomponentswithtag) but expects there to be one result, and returns that one result, or throws exception if there is any other number of matches besides one. + +* * * + +### `scryRenderedComponentsWithType()` + +```javascript +scryRenderedComponentsWithType( + tree, + componentClass +) +``` + +Finds all instances of components with type equal to `componentClass`. + +* * * + +### `findRenderedComponentWithType()` + +```javascript +findRenderedComponentWithType( + tree, + componentClass +) +``` + +Same as [`scryRenderedComponentsWithType()`](#scryrenderedcomponentswithtype) but expects there to be one result and returns that one result, or throws exception if there is any other number of matches besides one. + +* * * + +## Shallow Rendering + +### `createRenderer()` + +```javascript +createRenderer() +``` + +Call this in your tests to create a [shallow renderer](#shallow-rendering). + +* * * + +### `shallowRenderer.render()` + +```javascript +shallowRenderer.render( + element +) +``` + +Similar to [`ReactDOM.render`](/react/docs/react-dom.html#render) but it doesn't require DOM and only renders a single level deep. See [Shallow Rendering](#shallow-rendering). + +* * * + +### `shallowRenderer.getRenderOutput()` + +```javascript +shallowRenderer.getRenderOutput() +``` + +After [`shallowRenderer.render()`](#shallowrenderer.render) has been called, returns shallowly rendered output. diff --git a/docs/docs/10.2-form-input-binding-sugar.md b/docs/docs/addons-two-way-binding-helpers.md similarity index 71% rename from docs/docs/10.2-form-input-binding-sugar.md rename to docs/docs/addons-two-way-binding-helpers.md index 5ac0f27ce4..c919990ce6 100644 --- a/docs/docs/10.2-form-input-binding-sugar.md +++ b/docs/docs/addons-two-way-binding-helpers.md @@ -1,16 +1,27 @@ --- id: two-way-binding-helpers -title: Two-Way Binding Helpers +title: Two-way Binding Helpers permalink: docs/two-way-binding-helpers.html -prev: animation.html -next: test-utils.html +layout: docs +category: Add-Ons +prev: pure-render-mixin.html +next: update.html --- -`ReactLink` is an easy way to express two-way binding with React. - > Note: -> -> ReactLink is deprecated as of React v15. The recommendation is to explicitly set the value and change handler, instead of using ReactLink. +> `LinkedStateMixin` is deprecated as of React v15. The recommendation is to explicitly set the value and change handler, instead of using `LinkedStateMixin`. + +**Importing** + +```javascript +import LinkedStateMixin from 'react-addons-linked-state-mixin' // ES6 +var LinkedStateMixin = require('react-addons-linked-state-mixin') // ES5 with npm +var LinkedStateMixin = React.addons.LinkedStateMixin; // ES5 with react-with-addons.js +``` + +## Overview + +`LinkedStateMixin` is an easy way to express two-way binding with React. In React, data flows one way: from owner to child. This is because data only flows one direction in [the Von Neumann model of computing](https://en.wikipedia.org/wiki/Von_Neumann_architecture). You can think of it as "one-way data binding." @@ -18,15 +29,15 @@ However, there are lots of applications that require you to read some data and f In React, you would implement this by listening to a "change" event, read from your data source (usually the DOM) and call `setState()` on one of your components. "Closing the data flow loop" explicitly leads to more understandable and easier-to-maintain programs. See [our forms documentation](/react/docs/forms.html) for more information. -Two-way binding -- implicitly enforcing that some value in the DOM is always consistent with some React `state` -- is concise and supports a wide variety of applications. We've provided `ReactLink`: syntactic sugar for setting up the common data flow loop pattern described above, or "linking" some data source to React `state`. +Two-way binding -- implicitly enforcing that some value in the DOM is always consistent with some React `state` -- is concise and supports a wide variety of applications. We've provided `LinkedStateMixin`: syntactic sugar for setting up the common data flow loop pattern described above, or "linking" some data source to React `state`. > Note: > -> `ReactLink` is just a thin wrapper and convention around the `onChange`/`setState()` pattern. It doesn't fundamentally change how data flows in your React application. +> `LinkedStateMixin` is just a thin wrapper and convention around the `onChange`/`setState()` pattern. It doesn't fundamentally change how data flows in your React application. -## ReactLink: Before and After +## LinkedStateMixin: Before and After -Here's a simple form example without using `ReactLink`: +Here's a simple form example without using `LinkedStateMixin`: ```javascript var NoLink = React.createClass({ @@ -43,11 +54,9 @@ var NoLink = React.createClass({ }); ``` -This works really well and it's very clear how data is flowing, however, with a lot of form fields it could get a bit verbose. Let's use `ReactLink` to save us some typing: +This works really well and it's very clear how data is flowing, however, with a lot of form fields it could get a bit verbose. Let's use `LinkedStateMixin` to save us some typing: ```javascript{4,9} -var LinkedStateMixin = require('react-addons-linked-state-mixin'); - var WithLink = React.createClass({ mixins: [LinkedStateMixin], getInitialState: function() { @@ -59,9 +68,9 @@ var WithLink = React.createClass({ }); ``` -`LinkedStateMixin` adds a method to your React component called `linkState()`. `linkState()` returns a `ReactLink` object which contains the current value of the React state and a callback to change it. +`LinkedStateMixin` adds a method to your React component called `linkState()`. `linkState()` returns a `valueLink` object which contains the current value of the React state and a callback to change it. -`ReactLink` objects can be passed up and down the tree as props, so it's easy (and explicit) to set up two-way binding between a component deep in the hierarchy and state that lives higher in the hierarchy. +`valueLink` objects can be passed up and down the tree as props, so it's easy (and explicit) to set up two-way binding between a component deep in the hierarchy and state that lives higher in the hierarchy. Note that checkboxes have a special behavior regarding their `value` attribute, which is the value that will be sent on form submit if the checkbox is checked (defaults to `on`). The `value` attribute is not updated when the checkbox is checked or unchecked. For checkboxes, you should use `checkedLink` instead of `valueLink`: ``` @@ -70,9 +79,9 @@ Note that checkboxes have a special behavior regarding their `value` attribute, ## Under the Hood -There are two sides to `ReactLink`: the place where you create the `ReactLink` instance and the place where you use it. To prove how simple `ReactLink` is, let's rewrite each side separately to be more explicit. +There are two sides to `LinkedStateMixin`: the place where you create the `valueLink` instance and the place where you use it. To prove how simple `LinkedStateMixin` is, let's rewrite each side separately to be more explicit. -### ReactLink Without LinkedStateMixin +### valueLink Without LinkedStateMixin ```javascript{5-7,9-12} var WithoutMixin = React.createClass({ @@ -92,9 +101,9 @@ var WithoutMixin = React.createClass({ }); ``` -As you can see, `ReactLink` objects are very simple objects that just have a `value` and `requestChange` prop. And `LinkedStateMixin` is similarly simple: it just populates those fields with a value from `this.state` and a callback that calls `this.setState()`. +As you can see, `valueLink` objects are very simple objects that just have a `value` and `requestChange` prop. And `LinkedStateMixin` is similarly simple: it just populates those fields with a value from `this.state` and a callback that calls `this.setState()`. -### ReactLink Without valueLink +### LinkedStateMixin Without valueLink ```javascript var LinkedStateMixin = require('react-addons-linked-state-mixin'); diff --git a/docs/docs/10.7-update.md b/docs/docs/addons-update.md similarity index 86% rename from docs/docs/10.7-update.md rename to docs/docs/addons-update.md index e76f47ac19..d14cb90e91 100644 --- a/docs/docs/10.7-update.md +++ b/docs/docs/addons-update.md @@ -2,15 +2,28 @@ id: update title: Immutability Helpers permalink: docs/update.html -prev: create-fragment.html -next: pure-render-mixin.html +layout: docs +category: Add-Ons --- -React lets you use whatever style of data management you want, including mutation. However, if you can use immutable data in performance-critical parts of your application it's easy to implement a fast `shouldComponentUpdate()` method to significantly speed up your app. +> Note: +> `update` is a legacy add-on. Use [kolodny/immutability-helper](https://github.com/kolodny/immutability-helper) instead. + +**Importing** + +```javascript +import update from 'react-addons-update'; // ES6 +var update = require('react-addons-update'); // ES5 with npm +var update = React.addons.update; // ES5 with react-with-addons.js +``` + +## Overview + +React lets you use whatever style of data management you want, including mutation. However, if you can use immutable data in performance-critical parts of your application it's easy to implement a fast [`shouldComponentUpdate()`](/react/docs/react-component.html#shouldcomponentupdate) method to significantly speed up your app. Dealing with immutable data in JavaScript is more difficult than in languages designed for it, like [Clojure](http://clojure.org/). However, we've provided a simple immutability helper, `update()`, that makes dealing with this type of data much easier, *without* fundamentally changing how your data is represented. You can also take a look at Facebook's [Immutable-js](https://facebook.github.io/immutable-js/docs/) and the [Advanced Performance](/react/docs/advanced-performance.html) section for more detail on Immutable-js. -## The main idea +### The Main Idea If you mutate data like this: @@ -41,10 +54,12 @@ var newData = extend(myData, { While this is fairly performant (since it only makes a shallow copy of `log n` objects and reuses the rest), it's a big pain to write. Look at all the repetition! This is not only annoying, but also provides a large surface area for bugs. +## `update()` + `update()` provides simple syntactic sugar around this pattern to make writing this code easier. This code becomes: ```js -var update = require('react-addons-update'); +import update from 'react-addons-update'; var newData = update(myData, { x: {y: {z: {$set: 7}}}, @@ -56,7 +71,7 @@ While the syntax takes a little getting used to (though it's inspired by [MongoD The `$`-prefixed keys are called *commands*. The data structure they are "mutating" is called the *target*. -## Available commands +## Available Commands * `{$push: array}` `push()` all the items in `array` on the target. * `{$unshift: array}` `unshift()` all the items in `array` on the target. @@ -94,7 +109,7 @@ var newObj = update(obj, {b: {$apply: function(x) {return x * 2;}}}); var newObj2 = update(obj, {b: {$set: obj.b * 2}}); ``` -### (Shallow) merge +### (Shallow) Merge ```js var obj = {a: 5, b: 3}; diff --git a/docs/docs/addons.md b/docs/docs/addons.md new file mode 100644 index 0000000000..a927a4266a --- /dev/null +++ b/docs/docs/addons.md @@ -0,0 +1,44 @@ +--- +id: addons +title: Add-Ons +permalink: docs/addons.html +--- + +The React add-ons are a collection of useful utility modules for building React apps. **These should be considered experimental** and tend to change more often than the core. + +- [`TransitionGroup` and `CSSTransitionGroup`](animation.html), for dealing with animations and transitions that are usually not simple to implement, such as before a component's removal. +- [`createFragment`](create-fragment.html), to create a set of externally-keyed children. + +The add-ons below are in the development (unminified) version of React only: + +- [`Perf`](perf.html), a performance profiling tool for finding optimization opportunities. +- [`ReactTestUtils`](test-utils.html), simple helpers for writing test cases. + +### Legacy Add-ons + +The add-ons below are considered legacy and their use is discouraged. + +- [`PureRenderMixin`](pure-render-mixin.html). Use [`React.PureComponent`](/react/docs/react-api.html#react.purecomponent) instead. +- [`shallowCompare`](shallow-compare.html), a helper function that performs a shallow comparison for props and state in a component to decide if a component should update. +- [`update`](update.html). Use [`kolodny/immutability-helper`](https://github.com/kolodny/immutability-helper) instead. + +### Deprecated Add-ons + +[`LinkedStateMixin`](two-way-binding-helpers.html) has been deprecated. + +## Using React with Add-ons + +If using npm, you can install the add-ons individually from npm (e.g. `npm install react-addons-test-utils`) and import them: + +```javascript +import Perf from 'react-addons-perf'; // ES6 +var Perf = require('react-addons-perf'); // ES5 with npm +``` + +When using a CDN, you can use `react-with-addons.js` instead of `react.js`: + +```html + +``` + +The add-ons will be available via the `React.addons` global (e.g. `React.addons.TestUtils`). diff --git a/docs/docs/components-and-props.md b/docs/docs/components-and-props.md new file mode 100644 index 0000000000..98bf874421 --- /dev/null +++ b/docs/docs/components-and-props.md @@ -0,0 +1,258 @@ +--- +id: components-and-props +title: Components and Props +permalink: docs/components-and-props.html +redirect_from: "/docs/reusable-components.html" +redirect_from: "/docs/transferring-props.html" +redirect_from: "/tips/props-in-getInitialState-as-anti-pattern.html" +redirect_from: "/tips/communicate-between-components.html" +prev: rendering-elements.html +next: state-and-lifecycle.html +--- + +Components let you split the UI into independent, reusable pieces, and think about each piece in isolation. + +Conceptually, components are like JavaScript functions. They accept arbitrary inputs (called "props") and return React elements describing what should appear on the screen. + +## Functional and Class Components + +The simplest way to define a component is to write a JavaScript function: + +```js +function Welcome(props) { + return

                        Hello, {props.name}

                        ; +} +``` + +This function is a valid React component because it accepts a single "props" object argument with data and returns a React element. We call such components "functional" because they are literally JavaScript functions. + +You can also use an [ES6 class](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes) to define a component: + +```js +class Welcome extends React.Component { + render() { + return

                        Hello, {this.props.name}

                        ; + } +} +``` + +The above two components are equivalent from React's point of view. + +Classes have some additional features that we will discuss in the [next sections](/react/docs/state-and-lifecycle.html). Until then, we will use functional components for their conciseness. + +## Rendering a Component + +Previously, we only encountered React elements that represent DOM tags: + +```js +const element =
                        ; +``` + +However, elements can also represent user-defined components: + +```js +const element = ; +``` + +When React sees an element representing a user-defined component, it passes JSX attributes to this component as a single object. We call this object "props". + +For example, this code renders "Hello, Sara" on the page: + +```js{1,5} +function Welcome(props) { + return

                        Hello, {props.name}

                        ; +} + +const element = ; +ReactDOM.render( + element, + document.getElementById('root') +); +``` + +[Try it on CodePen.](http://codepen.io/gaearon/pen/YGYmEG?editors=0010) + +Let's recap what happens in this example: + +1. We call `ReactDOM.render()` with the `` element. +2. React calls the `Welcome` component with `{name: 'Sara'}` as the props. +3. Our `Welcome` component returns a `

                        Hello, Sara

                        ` element as the result. +4. React DOM efficiently updates the DOM to match `

                        Hello, Sara

                        `. + +>**Caveat:** +> +>Always start component names with a capital letter. +> +>For example, `
                        ` represents a DOM tag, but `` represents a component and requires `Welcome` to be in scope. + +## Composing Components + +Components can refer to other components in their output. This lets us use the same component abstraction for any level of detail. A button, a form, a dialog, a screen: in React apps, all those are commonly expressed as components. + +For example, we can create an `App` component that renders `Welcome` many times: + +```js{8-10} +function Welcome(props) { + return

                        Hello, {props.name}

                        ; +} + +function App() { + return ( +
                        + + + +
                        + ); +} + +ReactDOM.render( + , + document.getElementById('root') +); +``` + +[Try it on CodePen.](http://codepen.io/gaearon/pen/KgQKPr?editors=0010) + +Typically, new React apps have a single `App` component at the very top. However, if you integrate React into an existing app, you might start bottom-up with a small component like `Button` and gradually work your way to the top of the view hierarchy. + +>**Caveat:** +> +>Components must return a single root element. This is why we added a `
                        ` to contain all the `` elements. + +## Extracting Components + +Don't be afraid to split components into smaller components. + +For example, consider this `Comment` component: + +```js +function Comment(props) { + return ( +
                        +
                        + {props.author.name} +
                        + {props.author.name} +
                        +
                        +
                        + {props.text} +
                        +
                        + {formatDate(props.date)} +
                        +
                        + ); +} +``` + +[Try it on CodePen.](http://codepen.io/gaearon/pen/VKQwEo?editors=0010) + +It accepts `author` (an object), `text` (a string), and `date` (a date) as props, and describes a comment on a social media website. + +This component can be tricky to change because of all the nesting, and it is also hard to reuse individual parts of it. Let's extract a few components from it. + +First, we will extract `Avatar`: + +```js{3-5} +function Avatar(props) { + return ( + {props.user.name} + ); +} +``` + +The `Avatar` doesn't need to know that it is being rendered inside a `Comment`. This is why we have given its prop a more generic name: `user` rather than `author`. + +We recommend naming props from the component's own point of view rather than the context in which it is being used. + +We can now simplify `Comment` a tiny bit: + +```js{5} +function Comment(props) { + return ( +
                        +
                        + +
                        + {props.author.name} +
                        +
                        +
                        + {props.text} +
                        +
                        + {formatDate(props.date)} +
                        +
                        + ); +} +``` + +Next, we will extract a `UserInfo` component that renders an `Avatar` next to user's name: + +```js{3-8} +function UserInfo(props) { + return ( +
                        + +
                        + {props.user.name} +
                        +
                        + ); +} +``` + +This lets us simplify `Comment` even further: + +```js{4} +function Comment(props) { + return ( +
                        + +
                        + {props.text} +
                        +
                        + {formatDate(props.date)} +
                        +
                        + ); +} +``` + +[Try it on CodePen.](http://codepen.io/gaearon/pen/rrJNJY?editors=0010) + +Extracting components might seem like grunt work at first, but having a palette of reusable components pays off in larger apps. A good rule of thumb is that if a part of your UI is used several times (`Button`, `Panel`, `Avatar`), or is complex enough on its own (`App`, `FeedStory`, `Comment`), it is a good candidate to be a reusable component. + +## Props are Read-Only + +Whether you declare a component [as a function or a class](#functional-and-class-components), it must never modify its own props. Consider this `sum` function: + +```js +function sum(a, b) { + return a + b; +} +``` + +Such functions are called ["pure"](https://en.wikipedia.org/wiki/Pure_function) because they do not attempt to change their inputs, and always return the same result for the same inputs. + +In contrast, this function is impure because it changes its own input: + +```js +function withdraw(account, amount) { + account.total -= amount; +} +``` + +React is pretty flexible but it has a single strict rule: + +**All React components must act like pure functions with respect to their props.** + +Of course, application UIs are dynamic and change over time. In the [next section](/react/docs/state-and-lifecycle.html), we will introduce a new concept of "state". State allows React components to change their output over time in response to user actions, network responses, and anything else, without violating this rule. diff --git a/docs/docs/composition-vs-inheritance.md b/docs/docs/composition-vs-inheritance.md new file mode 100644 index 0000000000..5190f5a9c6 --- /dev/null +++ b/docs/docs/composition-vs-inheritance.md @@ -0,0 +1,171 @@ +--- +id: composition-vs-inheritance +title: Composition vs Inheritance +permalink: docs/composition-vs-inheritance.html +redirect_from: "/docs/multiple-components.html" +prev: lifting-state-up.html +next: thinking-in-react.html +--- + +React has a powerful composition model, and we recommend using composition instead of inheritance to reuse code between components. + +In this section, we will consider a few problems where developers new to React often reach for inheritance, and show how we can solve them with composition. + +## Containment + +Some components don't know their children ahead of time. This is especially common for components like `Sidebar` or `Dialog` that represent generic "boxes". + +We recommend that such components use the special `children` prop to pass children elements directly into their output: + +```js{4} +function FancyBorder(props) { + return ( +
                        + {props.children} +
                        + ); +} +``` + +This lets other components pass arbitrary children to them by nesting the JSX: + +```js{4-9} +function WelcomeDialog() { + return ( + +

                        + Welcome +

                        +

                        + Thank you for visiting our spacecraft! +

                        +
                        + ); +} +``` + +[Try it on CodePen.](http://codepen.io/gaearon/pen/ozqNOV?editors=0010) + +Anything inside the `` JSX tag gets passed into the `FancyBorder` component as a `children` prop. Since `FancyBorder` renders `{props.children}` inside a `
                        `, the passed elements appear in the final output. + +While this is less common, sometimes you might need multiple "holes" in a component. In such cases you may come up with your own convention instead of using `children`: + +```js{5,8,18,21} +function SplitPane(props) { + return ( +
                        +
                        + {props.left} +
                        +
                        + {props.right} +
                        +
                        + ); +} + +function App() { + return ( + + } + right={ + + } /> + ); +} +``` + +[Try it on CodePen.](http://codepen.io/gaearon/pen/gwZOJp?editors=0010) + +React elements like `` and `` are just objects, so you can pass them as props like any other data. + +## Specialization + +Sometimes we think about components as being "special cases" of other components. For example, we might say that a `WelcomeDialog` is a special case of `Dialog`. + +In React, this is also achieved by composition, where a more "specific" component renders a more "generic" one and configures it with props: + +```js{5,8,16-18} +function Dialog(props) { + return ( + +

                        + {props.title} +

                        +

                        + {props.message} +

                        +
                        + ); +} + +function WelcomeDialog() { + return ( + + ); +} +``` + +[Try it on CodePen.](http://codepen.io/gaearon/pen/kkEaOZ?editors=0010) + +Composition works equally well for components defined as classes: + +```js{10,27-31} +function Dialog(props) { + return ( + +

                        + {props.title} +

                        +

                        + {props.message} +

                        + {props.children} +
                        + ); +} + +class SignUpDialog extends React.Component { + constructor(props) { + super(props); + this.handleChange = this.handleChange.bind(this); + this.handleSignUp = this.handleSignUp.bind(this); + this.state = {login: ''}; + } + + render() { + return ( + + + + + ); + } + + handleChange(e) { + this.setState({login: e.target.value}); + } + + handleSignUp() { + alert(`Welcome aboard, ${this.state.login}!`); + } +} +``` + +[Try it on CodePen.](http://codepen.io/gaearon/pen/gwZbYa?editors=0010) + +## So What About Inheritance? + +At Facebook, we use React in thousands of components, and we haven't found any use cases where we would recommend creating component inheritance hierarchies. + +Props and composition give you all the flexibility you need to customize a component's look and behavior in an explicit and safe way. Remember that components may accept arbitrary props, including primitive values, React elements, or functions. + +If you want to reuse non-UI functionality between components, we suggest extracting it into a separate JavaScript module. The components may import it and use that function, object, or a class, without extending it. diff --git a/docs/docs/conditional-rendering.md b/docs/docs/conditional-rendering.md new file mode 100644 index 0000000000..c2591e6d31 --- /dev/null +++ b/docs/docs/conditional-rendering.md @@ -0,0 +1,241 @@ +--- +id: conditional-rendering +title: Conditional Rendering +permalink: docs/conditional-rendering.html +prev: handling-events.html +next: lists-and-keys.html +redirect_from: "/tips/false-in-jsx.html" +--- + +In React, you can create distinct components that encapsulate behavior you need. Then, you can render only some of them, depending on the state of your application. + +Conditional rendering in React works the same way conditions work in JavaScript. Use JavaScript operators like [`if`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else) or the [conditional operator](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) to create elements representing the current state, and let React update the UI to match them. + +Consider these two components: + +```js +function UserGreeting(props) { + return

                        Welcome back!

                        ; +} + +function GuestGreeting(props) { + return

                        Please sign up.

                        ; +} +``` + +We'll create a `Greeting` component that displays either of these components depending on whether a user is logged in: + +```javascript{3-7,11,12} +function Greeting(props) { + const isLoggedIn = props.isLoggedIn; + if (isLoggedIn) { + return ; + } else { + return ; + } +} + +ReactDOM.render( + // Try changing to isLoggedIn={true}: + , + document.getElementById('root') +); +``` + +[Try it out on CodePen.](https://codepen.io/gaearon/pen/ZpVxNq?editors=0011) + +This example renders a different greeting depending on the value of `isLoggedIn` prop. + +### Element Variables + +You can use variables to store elements. This can help you conditionally render a part of the component while the rest of the output doesn't change. + +Consider these two new components representing Logout and Login buttons: + +```js +function LoginButton(props) { + return ( + + ); +} + +function LogoutButton(props) { + return ( + + ); +} +``` + +In the example below, we will create a [stateful component](/react/docs/state-and-lifecycle.html#adding-local-state-to-a-class) called `LoginControl`. + +It will render either `` or `` depending on its current state. It will also render a `` from the previous example: + +```javascript{20-25,29,30} +class LoginControl extends React.Component { + constructor(props) { + super(props); + this.handleLoginClick = this.handleLoginClick.bind(this); + this.handleLogoutClick = this.handleLogoutClick.bind(this); + this.state = {isLoggedIn: false}; + } + + handleLoginClick() { + this.setState({isLoggedIn: true}); + } + + handleLogoutClick() { + this.setState({isLoggedIn: false}); + } + + render() { + const isLoggedIn = this.state.isLoggedIn; + + let button = null; + if (isLoggedIn) { + button = ; + } else { + button = ; + } + + return ( +
                        + + {button} +
                        + ); + } +} + +ReactDOM.render( + , + document.getElementById('root') +); +``` + +[Try it out on CodePen.](https://codepen.io/gaearon/pen/QKzAgB?editors=0010) + +While declaring a variable and using an `if` statement is a fine way to conditionally render a component, sometimes you might want to use a shorter syntax. There are a few ways to inline conditions in JSX, explained below. + +### Inline If with Logical && Operator + +You may [embed any expressions in JSX](/react/docs/introducing-jsx.html#embedding-expressions-in-jsx) by wrapping them in curly braces. This includes the JavaScript logical `&&` operator. It can be handy for conditionally including an element: + +```js{6-10} +function Mailbox(props) { + const unreadMessages = props.unreadMessages; + return ( +
                        +

                        Hello!

                        + {unreadMessages.length > 0 && +

                        + You have {unreadMessages.length} unread messages. +

                        + } +
                        + ); +} + +const messages = ['React', 'Re: React', 'Re:Re: React']; +ReactDOM.render( + , + document.getElementById('root') +); +``` + +[Try it on CodePen.](https://codepen.io/gaearon/pen/ozJddz?editors=0010) + +It works because in JavaScript, `true && expression` always evaluates to `expression`, and `false && expression` always evaluates to `false`. + +Therefore, if the condition is `true`, the element right after `&&` will appear in the output. If it is `false`, React will ignore and skip it. + +### Inline If-Else with Conditional Operator + +Another method for conditionally rendering elements inline is to use the JavaScript conditional operator [`condition ? true : false`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Conditional_Operator). + +In the example below, we use it to conditionally render a small block of text. + +```javascript{5} +render() { + const isLoggedIn = this.state.isLoggedIn; + return ( +
                        + The user is {isLoggedIn ? 'currently' : 'not'} logged in. +
                        + ); +} +``` + +It can also be used for larger expressions although it is less obvious what's going on: + +```js{5,7,9} +render() { + const isLoggedIn = this.state.isLoggedIn; + return ( +
                        + {isLoggedIn ? ( + + ) : ( + + )} +
                        + ); +} +``` + +Just like in JavaScript, it is up to you to choose an appropriate style based on what you and your team consider more readable. Also remember that whenever conditions become too complex, it might be a good time to [extract a component](/react/docs/components-and-props.html#extracting-components). + +### Preventing Component from Rendering + +In rare cases you might want a component to hide itself even though it was rendered by another component. To do this return `null` instead of its render output. + +In the example below, the `` is rendered depending on the value of the prop called `warn`. If the value of the prop is `false`, then the component does not render: + +```javascript{2-4,29} +function WarningBanner(props) { + if (!props.warn) { + return null; + } + + return ( +
                        + Warning! +
                        + ); +} + +class Page extends React.Component { + constructor(props) { + super(props); + this.state = {showWarning: true} + this.handleToggleClick = this.handleToggleClick.bind(this); + } + + handleToggleClick() { + this.setState(prevState => ({ + showWarning: !prevState.showWarning + })); + } + + render() { + return ( +
                        + + +
                        + ); + } +} + +ReactDOM.render( + , + document.getElementById('root') +); +``` + +[Try it out on CodePen.](https://codepen.io/gaearon/pen/Xjoqwm?editors=0010) diff --git a/docs/docs/12-context.md b/docs/docs/context.md similarity index 52% rename from docs/docs/12-context.md rename to docs/docs/context.md index 1cbc378185..499b341601 100644 --- a/docs/docs/12-context.md +++ b/docs/docs/context.md @@ -2,24 +2,26 @@ id: context title: Context permalink: docs/context.html -prev: advanced-performance.html --- -One of React's biggest strengths is that it's easy to track the flow of data through your React components. When you look at a component, you can easily see exactly which props are being passed in which makes your apps easy to reason about. +With React, it's easy to track the flow of data through your React components. When you look at a component, you can see which props are being passed, which makes your apps easy to reason about. -Occasionally, you want to pass data through the component tree without having to pass the props down manually at every level. React's "context" feature lets you do this. +In some cases, you want to pass data through the component tree without having to pass the props down manually at every level. +You can do this directly in React with the powerful "context" API. -> Note: -> -> Context is an advanced and experimental feature. The API is likely to change in future releases. -> -> Most applications will never need to use context. Especially if you are just getting started with React, you likely do not want to use context. Using context will make your code harder to understand because it makes the data flow less clear. It is similar to using global variables to pass state through your application. -> -> **If you have to use context, use it sparingly.** -> -> Regardless of whether you're building an application or a library, try to isolate your use of context to a small area and avoid using the context API directly when possible so that it's easier to upgrade when the API changes. +## Why Not To Use Context -## Passing info automatically through a tree +The vast majority of applications do not need to use context. + +If you want your application to be stable, don't use context. It is an experimental API and it is likely to break in future releases of React. + +If you aren't familiar with state management libraries like [Redux](https://github.com/reactjs/redux) or [MobX](https://github.com/mobxjs/mobx), don't use context. For many practical applications, these libraries and their React bindings are a good choice for managing state that is relevant to many components. It is far more likely that Redux is the right solution to your problem than that context is the right solution. + +If you aren't an experienced React developer, don't use context. There is usually a better way to implement functionality just using props and state. + +If you insist on using context despite these warnings, try to isolate your use of context to a small area and avoid using the context API directly when possible so that it's easier to upgrade when the API changes. + +## How To Use Context Suppose you have a structure like: @@ -55,7 +57,7 @@ class MessageList extends React.Component { } ``` -In this example, we manually thread through a `color` prop in order to style the `Button` and `Message` components appropriately. Theming is a good example of when you might want an entire subtree to have access to some piece of information (a color). Using context, we can pass this through the tree automatically: +In this example, we manually thread through a `color` prop in order to style the `Button` and `Message` components appropriately. Using context, we can pass this through the tree automatically: ```javascript{4,11-13,19,26-28,38-40} class Button extends React.Component { @@ -104,29 +106,35 @@ By adding `childContextTypes` and `getChildContext` to `MessageList` (the contex If `contextTypes` is not defined, then `context` will be an empty object. -## Parent-child coupling +## Parent-Child Coupling -Context can also let you build an API such as: +Context can also let you build an API where parents and children communicate. For example, one library that works this way is [React Router V4](https://react-router.now.sh/basic): ```javascript - - aubergine - butternut squash - clementine - +const BasicExample = () => ( + +
                        +
                          +
                        • Home
                        • +
                        • About
                        • +
                        • Topics
                        • +
                        + +
                        + + + + +
                        +
                        +) ``` -By passing down the relevant info in the `Menu` component, each `MenuItem` can communicate back to the containing `Menu` component. +By passing down some information from the `Router` component, each `Link` and `Match` can communicate back to the containing `Router`. -**Before you build components with this API, consider if there are cleaner alternatives.** We're fond of simply passing the items as an array in cases like this: +Before you build components with an API similar to this, consider if there are cleaner alternatives. For example, you can pass entire React component as props if you'd like to. -```javascript - -``` - -Recall that you can also pass entire React components in props if you'd like to. - -## Referencing context in lifecycle methods +## Referencing Context in Lifecycle Methods If `contextTypes` is defined within a component, the following lifecycle methods will receive an additional parameter, the `context` object: @@ -148,9 +156,9 @@ void componentDidUpdate( ) ``` -## Referencing context in stateless functional components +## Referencing Context in Stateless Functional Components -Stateless functional components are also able to reference `context` if `contextTypes` is defined as a property of the function. The following code shows the `Button` component above written as a stateless functional component. +Stateless functional components are also able to reference `context` if `contextTypes` is defined as a property of the function. The following code shows a `Button` component written as a stateless functional component. ```javascript const Button = ({children}, context) => @@ -161,7 +169,11 @@ const Button = ({children}, context) => Button.contextTypes = {color: React.PropTypes.string}; ``` -## Updating context +## Updating Context + +Don't do it. + +React has an API to update context, but it is fundamentally broken and you should not use it. The `getChildContext` function will be called when the state or props changes. In order to update data in the context, trigger a local state update with `this.setState`. This will trigger a new context and changes will be received by the children. @@ -198,14 +210,4 @@ MediaQuery.childContextTypes = { }; ``` -## When not to use context - -Just as global variables are best avoided when writing clear code, you should avoid using context in most cases. In particular, think twice before using it to "save typing" and using it instead of passing explicit props. - -The best use cases for context are for implicitly passing down the logged-in user, the current language, or theme information. All of these might otherwise be true globals, but context lets you scope them to a single React subtree. - -Do not use context to pass your model data through components. Threading your data through the tree explicitly is much easier to understand. Using context makes your components more coupled and less reusable, because they behave differently depending on where they're rendered. - -## Known limitations - -If a context value provided by a component changes, descendants that use that value won't update if an intermediate parent returns `false` from `shouldComponentUpdate`. See issue [#2517](https://github.com/facebook/react/issues/2517) for more details. +The problem is, if a context value provided by component changes, descendants that use that value won't update if an intermediate parent returns `false` from `shouldComponentUpdate`. This is totally out of control of the components using context, so there's basically no way to reliably update the context. [This blog post](https://medium.com/@mweststrate/how-to-safely-use-react-context-b7e343eff076) has a good explanation of why this is a problem and how you might get around it. diff --git a/docs/docs/flux-overview.it-IT.md b/docs/docs/flux-overview.it-IT.md deleted file mode 100644 index 2bb67265a1..0000000000 --- a/docs/docs/flux-overview.it-IT.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -id: flux-overview-it-IT -title: Architettura di un'Applicazione Flux -permalink: docs/flux-overview-it-IT.html ---- - -Questa pagina è stata spostata sul sito di Flux. [Leggila qui](https://facebook.github.io/flux/docs/overview.html). diff --git a/docs/docs/flux-overview.ko-KR.md b/docs/docs/flux-overview.ko-KR.md deleted file mode 100644 index f850069207..0000000000 --- a/docs/docs/flux-overview.ko-KR.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -id: flux-overview-ko-KR -title: Flux 애플리케이션 아키텍쳐 -permalink: docs/flux-overview-ko-KR.html ---- - -이 페이지는 Flux 웹사이트로 이동되었습니다. [거기서 보세요](https://facebook.github.io/flux/docs/overview.html). diff --git a/docs/docs/flux-overview.md b/docs/docs/flux-overview.md deleted file mode 100644 index 69909f67db..0000000000 --- a/docs/docs/flux-overview.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -id: flux-overview -title: Flux Application Architecture -permalink: docs/flux-overview.html ---- - -This page has been moved to the Flux website. [View it there](https://facebook.github.io/flux/docs/overview.html). diff --git a/docs/docs/flux-overview.zh-CN.md b/docs/docs/flux-overview.zh-CN.md deleted file mode 100644 index 77242bf755..0000000000 --- a/docs/docs/flux-overview.zh-CN.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -id: flux-overview-zh-CN -title: Flux 应用架构 -permalink: docs/flux-overview-zh-CN.html ---- - -本页被移到了 Flux 网站。[点击访问](https://facebook.github.io/flux/docs/overview.html)。 diff --git a/docs/docs/flux-todo-list.it-IT.md b/docs/docs/flux-todo-list.it-IT.md deleted file mode 100644 index 4adc5f6751..0000000000 --- a/docs/docs/flux-todo-list.it-IT.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -id: flux-todo-list-it-IT -title: Tutorial TodoMVC Flux -permalink: docs/flux-todo-list-it-IT.html ---- - -Questa pagina è stata spostata sul sito di Flux. [Leggila qui](https://facebook.github.io/flux/docs/todo-list.html). diff --git a/docs/docs/flux-todo-list.ko-KR.md b/docs/docs/flux-todo-list.ko-KR.md deleted file mode 100644 index 646b300824..0000000000 --- a/docs/docs/flux-todo-list.ko-KR.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -id: flux-todo-list-ko-KR -title: Flux TodoMVC 튜토리얼 -permalink: docs/flux-todo-list-ko-KR.html ---- - -이 페이지는 Flux 웹사이트로 이동되었습니다. [거기서 보세요](https://facebook.github.io/flux/docs/todo-list.html). diff --git a/docs/docs/flux-todo-list.md b/docs/docs/flux-todo-list.md deleted file mode 100644 index b265216e83..0000000000 --- a/docs/docs/flux-todo-list.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -id: flux-todo-list -title: Flux TodoMVC Tutorial -permalink: docs/flux-todo-list.html ---- - -This page has been moved to the Flux website. [View it there](https://facebook.github.io/flux/docs/todo-list.html). diff --git a/docs/docs/flux-todo-list.zh-CN.md b/docs/docs/flux-todo-list.zh-CN.md deleted file mode 100644 index 7ce5595011..0000000000 --- a/docs/docs/flux-todo-list.zh-CN.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -id: flux-todo-list-zh-CN -title: Flux TodoMVC 教程 -permalink: docs/flux-todo-list-zh-CN.html ---- - -本页被移到了 Flux 网站。[点击访问](https://facebook.github.io/flux/docs/todo-list.html)。 diff --git a/docs/docs/forms.md b/docs/docs/forms.md new file mode 100644 index 0000000000..81f7097f7b --- /dev/null +++ b/docs/docs/forms.md @@ -0,0 +1,428 @@ +--- +id: forms +title: Forms +permalink: docs/forms.html +prev: state-and-lifecycle.html +next: lifting-state-up.html +redirect_from: "/tips/controlled-input-null-value.html" +--- + +Form components such as ``, ` +``` + +For HTML, this easily allows developers to supply multiline values. However, since React is JavaScript, we do not have string limitations and can use `\n` if we want newlines. In a world where we have `value` and `defaultValue`, it is ambiguous what role children play. For this reason, you should not use children when setting ` ``` @@ -220,16 +253,16 @@ To make an uncontrolled component, `defaultValue` is used instead. > > You can pass an array into the `value` attribute, allowing you to select multiple options in a `select` tag: ` - +
                        ); } } -ReactDOM.render(
                        , document.getElementById('root')); +ReactDOM.render( + , + document.getElementById('root') +); ``` -[Try this on CodePen.](https://codepen.io/ericnakagawa/pen/pExQbL?editors=0010) +[Try it out on CodePen.](https://codepen.io/gaearon/pen/qawrbr?editors=0010) -### Basic Radio Button +### Uncontrolled Radio Button -```javascript +```javascript{25,34,35,44} class Form extends React.Component { constructor(props) { super(props); @@ -365,38 +414,53 @@ class Form extends React.Component { return (


                        -

                        - +
                        +
                        +
                        ); } } -ReactDOM.render(, document.getElementById('root')); +ReactDOM.render( + , + document.getElementById('root') +); ``` -[Try this on CodePen.](https://codepen.io/ericnakagawa/pen/WGaYVg?editors=0010) +[Try it out on CodePen.](https://codepen.io/gaearon/pen/ozOPLJ?editors=0010) +### Uncontrolled Checkbox -### Basic Uncontrolled Checkbox - -```javascript +```javascript{37,45,46,54} class Form extends React.Component { constructor(props) { super(props); @@ -406,10 +470,16 @@ class Form extends React.Component { } handleChange(event) { - let value = event.target.value; - let checked = this.state.checked; // copy - if (!checked[value]) { checked[value] = true; } else { checked[value] = false; } - this.setState({checked: checked}) + const value = event.target.value; + // Copy the object so we don't mutate the old state. + // (This requires an Object.assign polyfill): + const checked = Object.assign({}, this.state.checked) + if (!checked[value]) { + checked[value] = true; + } else { + checked[value] = false; + }; + this.setState({checked}); } handleSubmit(event) { @@ -424,36 +494,43 @@ class Form extends React.Component { return (


                        - -

                        - +
                        +
                        +
                        ); } } -ReactDOM.render(, document.getElementById('root')); + +ReactDOM.render( + , + document.getElementById('root') +); ``` -[Try it on CodePen.](https://codepen.io/ericnakagawa/pen/kkAzPO?editors=0010) - -### Form Events - -Event names: - -``` -onChange onInput onSubmit -``` +[Try it on CodePen.](https://codepen.io/gaearon/pen/rrbkWz?editors=0010) diff --git a/docs/docs/reference-events.md b/docs/docs/reference-events.md index b68e65c84b..6e275db9b5 100644 --- a/docs/docs/reference-events.md +++ b/docs/docs/reference-events.md @@ -35,7 +35,7 @@ string type > > As of v0.14, returning `false` from an event handler will no longer stop event propagation. Instead, `e.stopPropagation()` or `e.preventDefault()` should be triggered manually, as appropriate. -### Event pooling +### Event Pooling The `SyntheticEvent` is pooled. This means that the `SyntheticEvent` object will be reused and all properties will be nullified after the event callback has been invoked. This is for performance reasons. From ceb282a46dc9f5fc087b05697ee9e2a36707932c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=99=93=E5=8B=87?= Date: Thu, 27 Oct 2016 17:26:31 +0800 Subject: [PATCH 49/97] Update forms.md (#8121) --- docs/docs/forms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/forms.md b/docs/docs/forms.md index b9d8c0c658..df1c099745 100644 --- a/docs/docs/forms.md +++ b/docs/docs/forms.md @@ -98,7 +98,7 @@ Controlled components also let us reset inputs to arbitrary values by setting th ### Potential Issues With Checkboxes and Radio Buttons -Be aware that, in an attempt to normalize change handling for checkbox and radio inputs, React listens to a `click` browser event to implement the `onChange` event. +Be aware that, in an attempt to normalize change handling for checkboxes and radio inputs, React listens to a `click` browser event to implement the `onChange` event. For the most part this behaves as expected, except when calling `preventDefault` in a `change` handler. `preventDefault` stops the browser from visually updating the input, even if `checked` gets toggled. This can be worked around either by removing the call to `preventDefault`, or putting the toggle of `checked` in a `setTimeout`. From a8fc7d80e24cd371811ab7313a4a1e1dee438410 Mon Sep 17 00:00:00 2001 From: Varun Bhuvanendran Date: Thu, 27 Oct 2016 17:31:51 +0530 Subject: [PATCH 50/97] added word break (#8120) --- docs/css/react.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/css/react.scss b/docs/css/react.scss index 0874071736..3177f057e4 100644 --- a/docs/css/react.scss +++ b/docs/css/react.scss @@ -924,6 +924,7 @@ p a code { float: right; padding: 15px 20px; width: $columnWidth; + word-wrap: break-word; } .playgroundError { @@ -938,6 +939,7 @@ p a code { .MarkdownEditor .content { white-space: pre-wrap; + word-break: break-word; } .hll { From 48949f35c503eb8195fe36639f158c14aff18ef1 Mon Sep 17 00:00:00 2001 From: Lewis Blackwood Date: Thu, 27 Oct 2016 13:01:04 +0100 Subject: [PATCH 51/97] Correct usage of formatName() function in docs (#8122) The code section above these changes defines a `formatName` function that expects a parameter `user`. The code section containing these changes incorrectly called `formatName(user.name)`. For those following along with CodePen, this section should correctly call `formatName(user)`. --- docs/docs/introducing-jsx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/introducing-jsx.md b/docs/docs/introducing-jsx.md index d05f1575ed..56e7b98e85 100644 --- a/docs/docs/introducing-jsx.md +++ b/docs/docs/introducing-jsx.md @@ -59,7 +59,7 @@ This means that you can use JSX inside of `if` statements and `for` loops, assig ```js{3,5} function getGreeting(user) { if (user) { - return

                        Hello, {formatName(user.name)}!

                        ; + return

                        Hello, {formatName(user)}!

                        ; } else { return

                        Hello, Stranger.

                        ; } From de4c0127ad018c2d08b2f8eef32dea3e3f802203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20M=C3=B6ller?= Date: Mon, 24 Oct 2016 09:07:10 +0200 Subject: [PATCH 52/97] Fix: Remove unneeded else branches from documentation examples --- docs/docs/conditional-rendering.md | 3 +-- docs/docs/introducing-jsx.md | 3 +-- docs/docs/lifting-state-up.md | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/docs/conditional-rendering.md b/docs/docs/conditional-rendering.md index 865f124aba..5955e62fa8 100644 --- a/docs/docs/conditional-rendering.md +++ b/docs/docs/conditional-rendering.md @@ -30,9 +30,8 @@ function Greeting(props) { const isLoggedIn = props.isLoggedIn; if (isLoggedIn) { return ; - } else { - return ; } + return ; } ReactDOM.render( diff --git a/docs/docs/introducing-jsx.md b/docs/docs/introducing-jsx.md index 56e7b98e85..75b9a5622d 100644 --- a/docs/docs/introducing-jsx.md +++ b/docs/docs/introducing-jsx.md @@ -60,9 +60,8 @@ This means that you can use JSX inside of `if` statements and `for` loops, assig function getGreeting(user) { if (user) { return

                        Hello, {formatName(user)}!

                        ; - } else { - return

                        Hello, Stranger.

                        ; } + return

                        Hello, Stranger.

                        ; } ``` diff --git a/docs/docs/lifting-state-up.md b/docs/docs/lifting-state-up.md index 912ee89cdb..6b75c4ce7f 100644 --- a/docs/docs/lifting-state-up.md +++ b/docs/docs/lifting-state-up.md @@ -16,9 +16,8 @@ We will start with a component called `BoilingVerdict`. It accepts the `celsius` function BoilingVerdict(props) { if (props.celsius >= 100) { return

                        The water would boil.

                        ; - } else { - return

                        The water would not boil.

                        ; } + return

                        The water would not boil.

                        ; } ``` From 445ded0e3b9e9d0f10759dcbd44c306fe6aaa3b0 Mon Sep 17 00:00:00 2001 From: Ivan Zotov Date: Thu, 27 Oct 2016 15:54:18 +0300 Subject: [PATCH 53/97] Improve devtools image size for the tutorial (#8114) --- docs/img/tutorial/devtools.png | Bin 51403 -> 24215 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/img/tutorial/devtools.png b/docs/img/tutorial/devtools.png index 7dcf3c6a9dbee0f94759f152a2703ff34f1e7afd..c0482c093ac386a970fb012f3efff7bf29d22011 100644 GIT binary patch literal 24215 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 G|Gxk-Tw_uI literal 51403 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 F{s(wPl(hf= From 04ebe6d8c1b6f66407b5633b7f1153520aa5d834 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Thu, 27 Oct 2016 14:21:34 +0100 Subject: [PATCH 54/97] Clarify how transition props work (#8124) --- docs/docs/addons-animation.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/docs/addons-animation.md b/docs/docs/addons-animation.md index 9b69d9136e..abae33397e 100644 --- a/docs/docs/addons-animation.md +++ b/docs/docs/addons-animation.md @@ -105,7 +105,9 @@ render() { + transitionAppearTimeout={500} + transitionEnter={false} + transitionLeave={false}>

                        Fading at Initial Mount

                        ); @@ -130,6 +132,8 @@ At the initial mount, all children of the `ReactCSSTransitionGroup` will `appear > Note: > > The prop `transitionAppear` was added to `ReactCSSTransitionGroup` in version `0.13`. To maintain backwards compatibility, the default value is set to `false`. +> +> However, the default values of `transitionEnter` and `transitionLeave` are `true` so you must specify `transitionEnterTimeout` and `transitionLeaveTimeout` by default. If you don't need either enter or leave animations, pass `transitionEnter={false}` or `transitionLeave={false}`. ### Custom Classes From 923aee7cf52a60b9c87b5e543e3a3088bedcb6cb Mon Sep 17 00:00:00 2001 From: Eugene Date: Thu, 27 Oct 2016 22:25:43 +0400 Subject: [PATCH 55/97] Update reference-react-component.md (#8126) line 320: For example, this code ensures that the `color` prop is a string --- docs/docs/reference-react-component.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/reference-react-component.md b/docs/docs/reference-react-component.md index 7e5d6d4a90..fa8b5de573 100644 --- a/docs/docs/reference-react-component.md +++ b/docs/docs/reference-react-component.md @@ -325,7 +325,7 @@ class CustomButton extends React.Component { } CustomButton.propTypes = { - name: React.PropTypes.string + color: React.PropTypes.string }; ``` From 5014781d215f37b52d78d9b609e00d8d028a1ecd Mon Sep 17 00:00:00 2001 From: Damien Soulard Date: Mon, 31 Oct 2016 14:01:06 +0100 Subject: [PATCH 56/97] update-unknown-warning-page - add a reason for the warning (#8131) * update-unknown-warning-page - add a reason for this warning * Minor tweaks --- docs/warnings/unknown-prop.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/warnings/unknown-prop.md b/docs/warnings/unknown-prop.md index 9f030a8200..eb7585f650 100644 --- a/docs/warnings/unknown-prop.md +++ b/docs/warnings/unknown-prop.md @@ -13,6 +13,8 @@ There are a couple of likely reasons this warning could be appearing: 3. React does not yet recognize the attribute you specified. This will likely be fixed in a future version of React. However, React currently strips all unknown attributes, so specifying them in your React app will not cause them to be rendered. +4. You are using a React component without an upper case. React interprets it as a DOM tag because [React JSX transform uses the upper vs. lower case convention to distinguish between user-defined components and DOM tags](/react/docs/jsx-in-depth.html#user-defined-components-must-be-capitalized). + --- To fix this, composite components should "consume" any prop that is intended for the composite component and not intended for the child component. Example: From b062596fd4a354207ca6a2a44e032622d757e56f Mon Sep 17 00:00:00 2001 From: Andrew Lo Date: Fri, 28 Oct 2016 19:31:01 -0400 Subject: [PATCH 57/97] In the community support doc, I noticed that the React Facebook (#8138) page link is broken since it's missing '.com'. --- docs/community/support.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/community/support.md b/docs/community/support.md index 2e7f9882eb..86e3c1be7a 100644 --- a/docs/community/support.md +++ b/docs/community/support.md @@ -25,6 +25,6 @@ If you need an answer right away, check out the [Reactiflux Discord](https://dis ## Facebook and Twitter -For the latest news about React, [like us on Facebook](https://facebook/react) and [follow **@reactjs** on Twitter](https://twitter.com/reactjs). In addition, you can use the [#reactjs](https://twitter.com/hashtag/reactjs) hashtag to see what others are saying or add to the conversation. +For the latest news about React, [like us on Facebook](https://facebook.com/react) and [follow **@reactjs** on Twitter](https://twitter.com/reactjs). In addition, you can use the [#reactjs](https://twitter.com/hashtag/reactjs) hashtag to see what others are saying or add to the conversation.
                        From e2a70ac0ea0a2dd574a5fa64a3791c9bc283db2c Mon Sep 17 00:00:00 2001 From: bel3atar Date: Mon, 31 Oct 2016 11:41:43 +0000 Subject: [PATCH 58/97] add missing verb (#8139) `why is an` should be `why it is an` --- docs/tutorial/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial/tutorial.md b/docs/tutorial/tutorial.md index 180ba05ed0..75e21aeb17 100644 --- a/docs/tutorial/tutorial.md +++ b/docs/tutorial/tutorial.md @@ -204,7 +204,7 @@ Square no longer keeps its own state; it receives its value from its parent `Boa ## Why Immutability Is Important -In the previous code example, I suggest using the `.slice()` operator to copy the `squares` array prior to making changes and to prevent mutating the existing array. Let's talk about what this means and why it an important concept to learn. +In the previous code example, I suggest using the `.slice()` operator to copy the `squares` array prior to making changes and to prevent mutating the existing array. Let's talk about what this means and why it is an important concept to learn. There are generally two ways for changing data. The first, and most common method in past, has been to *mutate* the data by directly changing the values of a variable. The second method is to replace the data with a new copy of the object that also includes desired changes. From d128b45c6ff3bd6fd5ad66d80c479a53b5302b45 Mon Sep 17 00:00:00 2001 From: Lee Sanghyeon Date: Sat, 29 Oct 2016 21:01:41 +0900 Subject: [PATCH 59/97] Update codebase-overview.md (#8142) * Update codebase-overview.md Fix the broken source code URL in 'Event System' section. * Update codebase-overview.md Re-fix link name --- docs/contributing/codebase-overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/codebase-overview.md b/docs/contributing/codebase-overview.md index 51bcf53759..54845ef069 100644 --- a/docs/contributing/codebase-overview.md +++ b/docs/contributing/codebase-overview.md @@ -397,7 +397,7 @@ Its source code is located in [`src/renderers/shared/fiber`](https://github.com/ ### Event System -React implements a synthetic event system which is agnostic of the renderers and works both with React DOM and React Native. Its source code is located in [`src/renderers/shared/stack/event`](https://github.com/facebook/react/tree/master/src/renderers/shared/stack/event). +React implements a synthetic event system which is agnostic of the renderers and works both with React DOM and React Native. Its source code is located in [`src/renderers/shared/shared/event`](https://github.com/facebook/react/tree/master/src/renderers/shared/shared/event). There is a [video with a deep code dive into it](https://www.youtube.com/watch?v=dRo_egw7tBc) (66 mins). From d7d9b81a8595448a865a458ce4eec4dd7e702a07 Mon Sep 17 00:00:00 2001 From: Skasi Date: Mon, 31 Oct 2016 12:42:02 +0100 Subject: [PATCH 60/97] Remove duplicated word in doc (#8157) Gets rid of an obsolete word in the documentation for "State and Lifecycle": "Consider the ticking clock example from the one of the previous sections." -> "Consider the ticking clock example from one of the previous sections." --- docs/docs/state-and-lifecycle.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/state-and-lifecycle.md b/docs/docs/state-and-lifecycle.md index c957c7faaf..ab585aff03 100644 --- a/docs/docs/state-and-lifecycle.md +++ b/docs/docs/state-and-lifecycle.md @@ -7,7 +7,7 @@ prev: components-and-props.html next: handling-events.html --- -Consider the ticking clock example from the [one of the previous sections](/react/docs/rendering-elements.html#updating-the-rendered-element). +Consider the ticking clock example from [one of the previous sections](/react/docs/rendering-elements.html#updating-the-rendered-element). So far we have only learned one way to update the UI. From 44550c374f81deec9cceee0a587c25be24a700b5 Mon Sep 17 00:00:00 2001 From: Alex Baumgertner Date: Mon, 7 Nov 2016 20:57:23 +0300 Subject: [PATCH 61/97] Fix method markdown highlight (#8218) --- docs/docs/reference-react-component.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/reference-react-component.md b/docs/docs/reference-react-component.md index fa8b5de573..ac809953f1 100644 --- a/docs/docs/reference-react-component.md +++ b/docs/docs/reference-react-component.md @@ -345,7 +345,7 @@ In particular, `this.props.children` is a special prop, typically defined by the The state contains data specific to this component that may change over time. The state is user-defined, and it should be a plain JavaScript object. -If you don't use it in `render(), it shouldn't be on the state. For example, you can put timer IDs directly on the instance. +If you don't use it in `render()`, it shouldn't be on the state. For example, you can put timer IDs directly on the instance. See [State and Lifecycle](/react/docs/state-and-lifecycle.html) for more information about the state. From dec8b62796ab73829f0afc6e9f64ea6104051e86 Mon Sep 17 00:00:00 2001 From: Rick Beerendonk Date: Thu, 27 Oct 2016 13:25:14 -0500 Subject: [PATCH 62/97] Add React Remote Conf 2016. (#8094) Add video links to some conferences. --- docs/community/conferences.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/community/conferences.md b/docs/community/conferences.md index 388b5fa6cf..39ac533c8a 100644 --- a/docs/community/conferences.md +++ b/docs/community/conferences.md @@ -37,7 +37,7 @@ April 16 in Amsterdam, The Netherlands ### ReactEurope 2016 June 2 & 3 in Paris, France -[Website](http://www.react-europe.org/) - [Schedule](http://www.react-europe.org/#schedule) +[Website](http://www.react-europe.org/) - [Schedule](http://www.react-europe.org/#schedule) - [Videos](https://www.youtube.com/channel/UCorlLn2oZfgOJ-FUcF2eZ1A/playlists) ### ReactRally 2016 August 25-26 in Salt Lake City, UT @@ -47,10 +47,10 @@ August 25-26 in Salt Lake City, UT ### ReactNext 2016 September 15 in Tel Aviv, Israel -[Website](http://react-next.com/) - [Schedule](http://react-next.com/#schedule) +[Website](http://react-next.com/) - [Schedule](http://react-next.com/#schedule) - [Videos](https://www.youtube.com/channel/UC3BT8hh3yTTYxbLQy_wbk2w) ### ReactNL 2016 -October 13 in Amsterdam, The Netherlands +October 13 in Amsterdam, The Netherlands - [Schedule](http://reactnl.org/#program) [Website](http://reactnl.org/) @@ -58,3 +58,8 @@ October 13 in Amsterdam, The Netherlands October 26-28 in Bratislava, Slovakia [Website](https://reactiveconf.com/) + +### React Remote Conf 2016 +October 26-28 online + +[Website](https://allremoteconfs.com/react-2016) - [Schedule](https://allremoteconfs.com/react-2016#schedule) \ No newline at end of file From b691f7448f182aa5addc42189e293f3f848ead45 Mon Sep 17 00:00:00 2001 From: Gant Laborde Date: Fri, 28 Oct 2016 13:21:21 -0500 Subject: [PATCH 63/97] Organize and add confs (#8129) Upcoming proximity followed by past chronological. --- docs/community/conferences.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/community/conferences.md b/docs/community/conferences.md index 39ac533c8a..0fcf2e6c8b 100644 --- a/docs/community/conferences.md +++ b/docs/community/conferences.md @@ -7,6 +7,26 @@ permalink: community/conferences.html redirect_from: "docs/conferences.html" --- +## Upcoming Conferences + +### ReactEurope 2017 +May 18th & 19th in Paris, France + +[Website](http://www.react-europe.org/) - [Schedule](http://www.react-europe.org/#schedule) + +### Chain React 2017 +Summer 2017, Portland, Oregon USA + +[Website](https://infinite.red/ChainReactConf) - [Twitter](https://twitter.com/chainreactconf) + +### React Native EU 2017 +Fall 2017, Poland + +[Website](http://react-native.eu/) + + +## Past Conferences + ### React.js Conf 2015 January 28 & 29 in Facebook HQ, CA @@ -62,4 +82,4 @@ October 26-28 in Bratislava, Slovakia ### React Remote Conf 2016 October 26-28 online -[Website](https://allremoteconfs.com/react-2016) - [Schedule](https://allremoteconfs.com/react-2016#schedule) \ No newline at end of file +[Website](https://allremoteconfs.com/react-2016) - [Schedule](https://allremoteconfs.com/react-2016#schedule) From 2692cf4f03bdc317fbac4249d6009564b56599e3 Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Thu, 3 Nov 2016 13:18:48 -0700 Subject: [PATCH 64/97] Add Agent Conference to conferences docs (#8196) * Add Agent Conference to conferences docs * Move Agent Conference to upcoming conferences --- docs/community/conferences.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/community/conferences.md b/docs/community/conferences.md index 0fcf2e6c8b..f81708d972 100644 --- a/docs/community/conferences.md +++ b/docs/community/conferences.md @@ -9,6 +9,11 @@ redirect_from: "docs/conferences.html" ## Upcoming Conferences +### Agent Conference 2017 +January 20-21 in Dornbirn, Austria + +[Website](http://agent.sh/) + ### ReactEurope 2017 May 18th & 19th in Paris, France From cc3b821f6638ba79ad810f61e85b551a61904cb5 Mon Sep 17 00:00:00 2001 From: Robert Haritonov Date: Tue, 8 Nov 2016 16:20:22 +0100 Subject: [PATCH 65/97] Add React Amsterdam 2017 (#8235) We've recently announced the dates for our next React Amsterdam edition, looking forward on adding it to the list. --- docs/community/conferences.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/community/conferences.md b/docs/community/conferences.md index f81708d972..bbcb19f460 100644 --- a/docs/community/conferences.md +++ b/docs/community/conferences.md @@ -19,6 +19,11 @@ May 18th & 19th in Paris, France [Website](http://www.react-europe.org/) - [Schedule](http://www.react-europe.org/#schedule) +### React Amsterdam 2017 +April 21st in Amsterdam, The Netherlands + +[Website](https://react.amsterdam) - [Twitter](https://twitter.com/reactamsterdam) + ### Chain React 2017 Summer 2017, Portland, Oregon USA @@ -57,7 +62,7 @@ February 22 & 23 in San Francisco, CA ### React Amsterdam 2016 April 16 in Amsterdam, The Netherlands -[Website](http://react.amsterdam) - [Videos](https://youtu.be/sXDZBxbRRag?list=PLNBNS7NRGKMG3uLrm5fgY02hJ87Wzb4IU) +[Website](https://react.amsterdam/2016) - [Videos](https://youtu.be/sXDZBxbRRag?list=PLNBNS7NRGKMG3uLrm5fgY02hJ87Wzb4IU) ### ReactEurope 2016 June 2 & 3 in Paris, France From 3fe1664601d670f6ac87f8cdd5fe26ac48b07cd7 Mon Sep 17 00:00:00 2001 From: Kevin Lacker Date: Tue, 8 Nov 2016 11:32:02 -0800 Subject: [PATCH 66/97] Docs: add a bunch of redirects (#8137) * add a bunch of redirects * add more redirects --- docs/docs/addons-animation.md | 4 ++++ docs/docs/components-and-props.md | 5 +++++ docs/docs/forms.md | 12 +++++++----- docs/docs/handling-events.md | 2 ++ docs/docs/hello-world.md | 2 ++ docs/docs/installation.md | 1 + docs/docs/jsx-in-depth.md | 2 ++ docs/docs/lifting-state-up.md | 3 +++ docs/docs/reference-dom-elements.md | 1 + docs/docs/reference-react-component.md | 2 ++ docs/docs/reference-react.md | 3 +++ docs/docs/refs-and-the-dom.md | 2 ++ docs/docs/thinking-in-react.md | 4 +++- docs/tutorial/tutorial.md | 3 +++ 14 files changed, 40 insertions(+), 6 deletions(-) diff --git a/docs/docs/addons-animation.md b/docs/docs/addons-animation.md index abae33397e..3cb1751734 100644 --- a/docs/docs/addons-animation.md +++ b/docs/docs/addons-animation.md @@ -6,6 +6,10 @@ layout: docs category: Add-Ons prev: addons.html next: create-fragment.html +redirect_from: + - "docs/animation-ja-JP.html" + - "docs/animation-ko-KR.html" + - "docs/animation-zh-CN.html" --- The [`ReactTransitionGroup`](#reacttransitiongroup) add-on component is a low-level API for animation, and [`ReactCSSTransitionGroup`](#reactcsstransitiongroup) is an add-on component for easily implementing basic CSS animations and transitions. diff --git a/docs/docs/components-and-props.md b/docs/docs/components-and-props.md index 0122d35947..150138fb91 100644 --- a/docs/docs/components-and-props.md +++ b/docs/docs/components-and-props.md @@ -4,7 +4,12 @@ title: Components and Props permalink: docs/components-and-props.html redirect_from: - "docs/reusable-components.html" + - "docs/reusable-components-zh-CN.html" - "docs/transferring-props.html" + - "docs/transferring-props-it-IT.html" + - "docs/transferring-props-ja-JP.html" + - "docs/transferring-props-ko-KR.html" + - "docs/transferring-props-zh-CN.html" - "tips/props-in-getInitialState-as-anti-pattern.html" - "tips/communicate-between-components.html" prev: rendering-elements.html diff --git a/docs/docs/forms.md b/docs/docs/forms.md index df1c099745..7916a08cb5 100644 --- a/docs/docs/forms.md +++ b/docs/docs/forms.md @@ -4,7 +4,9 @@ title: Forms permalink: docs/forms.html prev: state-and-lifecycle.html next: lifting-state-up.html -redirect_from: "tips/controlled-input-null-value.html" +redirect_from: + - "tips/controlled-input-null-value.html" + - "docs/forms-zh-CN.html" --- Form components such as ``, ` ``` -This renders an input *initialized* with the value, `Untitled`. When the user updates the input, the node's `value` *property* will change. However, `node.getAttribute('value')` will still return the value used at initialization time, `Untitled`. +In React, a ` -``` - -For HTML, this easily allows developers to supply multiline values. However, since React is JavaScript, we do not have string limitations and can use `\n` if we want newlines. In a world where we have `value` and `defaultValue`, it is ambiguous what role children play. For this reason, you should not use children when setting `