diff --git a/_config.yml b/_config.yml index e513d3df..7bf34c47 100644 --- a/_config.yml +++ b/_config.yml @@ -36,4 +36,4 @@ sass: sass_dir: _css gems: - jekyll-redirect-from -react_version: 0.14.3 +react_version: 0.14.6 diff --git a/_js/html-jsx.js b/_js/html-jsx.js index ade01466..4e6937bd 100644 --- a/_js/html-jsx.js +++ b/_js/html-jsx.js @@ -1,5 +1,5 @@ /** - * Copyright 2013-2015, Facebook, Inc. + * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the diff --git a/_posts/2014-10-16-react-v0.12-rc1.md b/_posts/2014-10-16-react-v0.12-rc1.md index 397ab691..c78c6378 100644 --- a/_posts/2014-10-16-react-v0.12-rc1.md +++ b/_posts/2014-10-16-react-v0.12-rc1.md @@ -41,7 +41,7 @@ We have wanted to do this since before we even open sourced React. No more `/** The React specific JSX transform no longer transforms to function calls. Instead we use `React.createElement` and pass it arguments. This allows us to make optimizations and better support React as a compile target for things like Om. Read more in the [React Elements introduction](/react/blog/2014/10/14/introducting-react-elements.html). -The result of this change is that we will no longer support arbitrary function calls. We understand that the ability to do was was a convenient shortcut for many people but we believe the gains will be worth it. +The result of this change is that we will no longer support arbitrary function calls. We understand that the ability to do was a convenient shortcut for many people but we believe the gains will be worth it. ### JSX Lower-case Convention diff --git a/_posts/2014-11-24-react-js-conf-updates.md b/_posts/2014-11-24-react-js-conf-updates.md index cd8908ad..e0cefeb9 100644 --- a/_posts/2014-11-24-react-js-conf-updates.md +++ b/_posts/2014-11-24-react-js-conf-updates.md @@ -17,7 +17,7 @@ stick with the originally planned format and venue on Facebook's campus. Unfortunately, this means that we can only accept a small number of the awesome conference talk proposals. In order to make sure attendees get a fair shot at -registering, we're going to to sell tickets in three separate first-come, +registering, we're going to sell tickets in three separate first-come, first-serve phases. **Tickets will cost $200 regardless of which phase they are purchased from and all proceeds will go to charity**. diff --git a/_posts/2015-12-29-react-v0.14.4.md b/_posts/2015-12-29-react-v0.14.4.md new file mode 100644 index 00000000..8356129e --- /dev/null +++ b/_posts/2015-12-29-react-v0.14.4.md @@ -0,0 +1,37 @@ +--- +title: "React v0.14.4" +author: spicyj +--- + +Happy December! We have a minor point release today. It has just a few small bug fixes. + +The release is now available for download: + +* **React** + Dev build with warnings: + Minified build for production: +* **React with Add-Ons** + Dev build with warnings: + Minified build for production: +* **React DOM** (include React in the page before React DOM) + Dev build with warnings: + Minified build for production: +* **React DOM Server** (include React in the page before React DOM Server) + Dev build with warnings: + Minified build for production: + +We've also published version `0.14.4` of the `react`, `react-dom`, and addons packages on npm and the `react` package on bower. + +- - - + +## Changelog + +### React +- Minor internal changes for better compatibility with React Native + +### React DOM +- The `autoCapitalize` and `autoCorrect` props are now set as attributes in the DOM instead of properties to improve cross-browser compatibility +- Fixed bug with controlled `` supports `defaultChecked` and `` and `` support `defaultChecked`, and ` this.myTextInput = ref} /> @@ -131,7 +133,7 @@ Refs are a great way to send a message to a particular child instance in a way t ### Cautions: -- *Never* access refs inside of any component's render method - or while any component's render method is even running anywhere in the call stack. +- *Never* access refs inside of any component's render method – or while any component's render method is even running anywhere in the call stack. - If you want to preserve Google Closure Compiler advanced-mode crushing resilience, make sure to never access as a property what was specified as a string. This means you must access using `this.refs['myRefString']` if your ref was defined as `ref="myRefString"`. -- If you have not programmed several apps with React, your first inclination is usually going to be to try to use refs to "make things happen" in your app. If this is the case, take a moment and think more critically about where `state` should be owned in the component hierarchy. Often, it becomes clear that the proper place to "own" that state is at a higher level in the hierarchy. Placing the state there often eliminates any desire to use `ref`s to "make things happen" – instead, the data flow will usually accomplish your goal. +- If you have not programmed several apps with React, your first inclination is usually going to be to try to use refs to "make things happen" in your app. If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy. Often, it becomes clear that the proper place to "own" that state is at a higher level in the hierarchy. Placing the state there often eliminates any desire to use `ref`s to "make things happen" – instead, the data flow will usually accomplish your goal. - Refs may not be attached to a [stateless function](/react/docs/reusable-components.html#stateless-functions), because the component does not have a backing instance. You can always wrap a stateless component in a standard composite component and attach a ref to the composite component. diff --git a/docs/10.4-test-utils.md b/docs/10.4-test-utils.md index cbbaa9d9..65d92f2b 100644 --- a/docs/10.4-test-utils.md +++ b/docs/10.4-test-utils.md @@ -232,6 +232,7 @@ After `render` has been called, returns shallowly rendered output. You can then Then you can assert: ```javascript +var renderer = ReactTestUtils.createRenderer(); result = renderer.getRenderOutput(); expect(result.type).toBe('div'); expect(result.props.children).toEqual([ diff --git a/docs/getting-started.md b/docs/getting-started.md index 5a388495..d9e44318 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -34,7 +34,7 @@ $ npm install --save react react-dom babelify babel-preset-react $ browserify -t [ babelify --presets [ react ] ] main.js -o bundle.js ``` -To install React DOM and build your bundle with webpack: +To install React DOM and build your bundle with webpack: ```sh $ npm install --save react react-dom babel-preset-react @@ -45,6 +45,15 @@ $ webpack > > If you are using ES2015, you will want to also use the `babel-preset-es2015` package. +**Note:** by default, React will be in development mode, which is slower, and not advised for production. To use React in production mode, set the environment variable `NODE_ENV` to `production` (using envify or webpack's DefinePlugin). For example: + +```js +new webpack.DefinePlugin({ + "process.env": { + NODE_ENV: JSON.stringify("production") + } +}); +``` ## Quick Start Without npm diff --git a/docs/ref-01-top-level-api.md b/docs/ref-01-top-level-api.md index 4fdcdfd5..7aeb7158 100644 --- a/docs/ref-01-top-level-api.md +++ b/docs/ref-01-top-level-api.md @@ -66,9 +66,7 @@ factoryFunction createFactory( ) ``` -Return a function that produces ReactElements of a given type. Like `React.createElement`, -the type argument can be either an html tag name string (eg. 'div', 'span', etc), or a -`ReactClass`. +Return a function that produces ReactElements of a given type. Like `React.createElement`, the type argument can be either an html tag name string (eg. 'div', 'span', etc), or a `ReactClass`. ### React.isValidElement diff --git a/docs/ref-03-component-specs.md b/docs/ref-03-component-specs.md index 2855caa7..9e5a9562 100644 --- a/docs/ref-03-component-specs.md +++ b/docs/ref-03-component-specs.md @@ -148,6 +148,8 @@ componentWillReceiveProps: function(nextProps) { > Note: > +> One common mistake is for code executed during this lifecycle method to assume that props have changed. To understand why this is invalid, read [A implies B does not imply B implies A](/react/blog/2016/01/08/A-implies-B-does-not-imply-B-implies-A.html) +> > There is no analogous method `componentWillReceiveState`. An incoming prop transition may cause a state change, but the opposite is not true. If you need to perform operations in response to a state change, use `componentWillUpdate`. @@ -161,8 +163,7 @@ boolean shouldComponentUpdate( Invoked before rendering when new props or state are being received. This method is not called for the initial render or when `forceUpdate` is used. -Use this as an opportunity to `return false` when you're certain that the -transition to the new props and state will not require a component update. +Use this as an opportunity to `return false` when you're certain that the transition to the new props and state will not require a component update. ```javascript shouldComponentUpdate: function(nextProps, nextState) { diff --git a/docs/ref-04-tags-and-attributes.md b/docs/ref-04-tags-and-attributes.md index 882e55c6..8481c75b 100644 --- a/docs/ref-04-tags-and-attributes.md +++ b/docs/ref-04-tags-and-attributes.md @@ -18,11 +18,11 @@ The following HTML elements are supported: a abbr address area article aside audio b base bdi bdo big blockquote body br button canvas caption cite code col colgroup data datalist dd del details dfn dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 -h6 head header hr html i iframe img input ins kbd keygen label legend li link -main map mark menu menuitem meta meter nav noscript object ol optgroup option -output p param picture pre progress q rp rt ruby s samp script section select -small source span strong style sub summary sup table tbody td textarea tfoot th -thead time title tr track u ul var video wbr +h6 head header hgroup hr html i iframe img input ins kbd keygen label legend li +link main map mark menu menuitem meta meter nav noscript object ol optgroup +option output p param picture pre progress q rp rt ruby s samp script section +select small source span strong style sub summary sup table tbody td textarea +tfoot th thead time title tr track u ul var video wbr ``` ### SVG elements @@ -30,11 +30,11 @@ thead time title tr track u ul var video wbr The following SVG elements are supported: ``` -circle clipPath defs ellipse g line linearGradient mask path pattern polygon polyline -radialGradient rect stop svg text tspan +circle clipPath defs ellipse g image line linearGradient mask path pattern +polygon polyline radialGradient rect stop svg text tspan ``` -You may also be interested in [react-art](https://github.com/facebook/react-art), a drawing library for React that can render to Canvas, SVG, or VML (for IE8). +You may also be interested in [react-art](https://github.com/facebook/react-art), a cross-browser drawing library for React. ## Supported Attributes @@ -53,24 +53,32 @@ These standard attributes are supported: ``` accept acceptCharset accessKey action allowFullScreen allowTransparency alt -async autoComplete autoFocus autoPlay capture cellPadding cellSpacing charSet -challenge checked classID className cols colSpan content contentEditable contextMenu -controls coords crossOrigin data dateTime defer dir disabled download draggable -encType form formAction formEncType formMethod formNoValidate formTarget frameBorder -headers height hidden high href hrefLang htmlFor httpEquiv icon id inputMode -keyParams keyType label lang list loop low manifest marginHeight marginWidth max -maxLength media mediaGroup method min minLength multiple muted name noValidate open -optimum pattern placeholder poster preload radioGroup readOnly rel required role -rows rowSpan sandbox scope scoped scrolling seamless selected shape size sizes -span spellCheck src srcDoc srcSet start step style summary tabIndex target title -type useMap value width wmode wrap +async autoComplete autoFocus autoPlay capture cellPadding cellSpacing challenge +charSet checked classID className colSpan cols content contentEditable +contextMenu controls coords crossOrigin data dateTime default defer dir +disabled download draggable encType form formAction formEncType formMethod +formNoValidate formTarget frameBorder headers height hidden high href hrefLang +htmlFor httpEquiv icon id inputMode integrity is keyParams keyType kind label +lang list loop low manifest marginHeight marginWidth max maxLength media +mediaGroup method min minLength multiple muted name noValidate nonce open +optimum pattern placeholder poster preload radioGroup readOnly rel required +reversed role rowSpan rows sandbox scope scoped scrolling seamless selected +shape size sizes span spellCheck src srcDoc srcLang srcSet start step style +summary tabIndex target title type useMap value width wmode wrap +``` + +These RDFa attributes are supported (several RDFa attributes overlap with standard HTML attributes and thus are excluded from this list): + +``` +about datatype inlist prefix property resource typeof vocab ``` In addition, the following non-standard attributes are supported: - `autoCapitalize autoCorrect` for Mobile Safari. -- `property` for [Open Graph](http://ogp.me/) meta tags. +- `color` for `` in Safari. - `itemProp itemScope itemType itemRef itemID` for [HTML5 microdata](http://schema.org/docs/gs.html). +- `security` for older versions of Internet Explorer. - `unselectable` for Internet Explorer. - `results autoSave` for WebKit/Blink input fields of type `search`. @@ -78,13 +86,6 @@ There is also the React-specific attribute `dangerouslySetInnerHTML` ([more here ### SVG Attributes -``` -clipPath cx cy d dx dy fill fillOpacity fontFamily -fontSize fx fy gradientTransform gradientUnits markerEnd -markerMid markerStart offset opacity patternContentUnits -patternUnits points preserveAspectRatio r rx ry spreadMethod -stopColor stopOpacity stroke strokeDasharray strokeLinecap -strokeOpacity strokeWidth textAnchor transform version -viewBox x1 x2 x xlinkActuate xlinkArcrole xlinkHref xlinkRole -xlinkShow xlinkTitle xlinkType xmlBase xmlLang xmlSpace y1 y2 y -``` +Any attributes passed to SVG tags are passed through without changes. + +React used to support special camelCase aliases for certain SVG attributes, such as `clipPath`. If you use them now you'll see a deprecation warning. These aliases will be removed in the next version in favor of their real names from the SVG specification, such as `clip-path`. Attributes that have a camelCase name in the spec, such as `gradientTransform`, will keep their names. diff --git a/docs/ref-05-events.md b/docs/ref-05-events.md index 50c86416..a751405a 100644 --- a/docs/ref-05-events.md +++ b/docs/ref-05-events.md @@ -61,8 +61,7 @@ function onClick(event) { ## Supported Events -React normalizes events so that they have consistent properties across -different browsers. +React normalizes events so that they have consistent properties across different browsers. The event handlers below are triggered by an event in the bubbling phase. To register an event handler for the capture phase, append `Capture` to the event name; for example, instead of using `onClick`, you would use `onClickCapture` to handle the click event in the capture phase. diff --git a/docs/ref-08-reconciliation.md b/docs/ref-08-reconciliation.md index 8e113d97..a249add2 100644 --- a/docs/ref-08-reconciliation.md +++ b/docs/ref-08-reconciliation.md @@ -13,7 +13,7 @@ React's key design decision is to make the API seem like it re-renders the whole Generating the minimum number of operations to transform one tree into another is a complex and well-studied problem. The [state of the art algorithms](http://grfia.dlsi.ua.es/ml/algorithms/references/editsurvey_bille.pdf) have a complexity in the order of O(n3) where n is the number of nodes in the tree. -This means that displaying 1000 nodes would require in the order of one billion comparisons. This is far too expensive for our use case. To put this number in perspective, CPUs nowadays execute roughly 3 billion instruction per second. So even with the most performant implementation, we wouldn't be able to compute that diff in less than a second. +This means that displaying 1000 nodes would require in the order of one billion comparisons. This is far too expensive for our use case. To put this number in perspective, CPUs nowadays execute roughly 3 billion instructions per second. So even with the most performant implementation, we wouldn't be able to compute that diff in less than a second. Since an optimal algorithm is not tractable, we implement a non-optimal O(n) algorithm using heuristics based on two assumptions: diff --git a/docs/thinking-in-react.it-IT.md b/docs/thinking-in-react.it-IT.md index d8e9cd28..7cc96b61 100644 --- a/docs/thinking-in-react.it-IT.md +++ b/docs/thinking-in-react.it-IT.md @@ -61,7 +61,7 @@ Adesso che abbiamo identificato i componenti nel nostro mock, organizziamoli in ## Passo 2: Costruisci una versione statica in React - + Adesso che hai la tua gerarchia di componenti, è venuto il momento di implementare la tua applicazione. La maniera più semplice è costruire una versione che prende il tuo modello di dati e visualizza la UI ma non è interattiva. È buona norma disaccoppiare questi processi perché costruire una versione statica richiede la scrittura di parecchio codice e poco pensare, mentre aggiungere l'interattività richiede un parecchio pensare ma non un granché di scrittura. Vedremo perché. @@ -105,7 +105,7 @@ Quindi, per concludere, il nostro stato è: ## Passo 4: Identifica dove debba risiedere il tuo stato - + OK, abbiamo dunque identificato quale sia l'insieme minimo dello stato dell'applicazione. Successivamente, dobbiamo identificare quale componente muta, o *possiede*, questo stato. @@ -130,7 +130,7 @@ Puoi cominciare a vedere come si comporterà la tua applicazione: imposta `filte ## Passo 5: Aggiungi il flusso dati inverso - + Finora abbiamo costruito un'applicazione che visualizza correttamente come una funzione di proprietà e stato che fluiscono verso il basso della gerarchia. Adesso è il momento di supportare il flusso dei dati nella direzione opposta: i componenti del modulo in profondità nella gerarchia devono aggiornare lo stato in `FilterableProductTable`. diff --git a/docs/thinking-in-react.ko-KR.md b/docs/thinking-in-react.ko-KR.md index 5c023db1..6476545a 100644 --- a/docs/thinking-in-react.ko-KR.md +++ b/docs/thinking-in-react.ko-KR.md @@ -61,7 +61,7 @@ React의 많은 뛰어난 점들 중 하나는 생각을 하면서 애플리케 ## 2단계: 정적 버전을 만드세요. - + 계층구조의 컴포넌트들을 가지고 있으니, 이젠 애플리케이션을 구현할 시간입니다. 가장 쉬운 방법은 상호작용을 하지 않는 채로 자료 모델을 이용해 UI를 그리는 것입니다. 정적 버전을 만드는 데에는 적은 생각과 많은 노동이 필요하고, 상호작용을 추가하는 데에는 많은 생각과 적은 노동이 필요하기 때문에 둘을 분리하는 것이 가장 좋습니다. 왜 그런지 봅시다. @@ -105,7 +105,7 @@ product 들의 원본 목록은 props를 통해서 전달되기 때문에, state ## 4단계: 어디서 state가 유지되어야 하는지 확인하세요. - + 이제 최소한의 state가 무엇인지 알아냈습니다. 다음은, 어떤 컴포넌트가 이 state를 변형하거나 만들어낼지 알아내야 합니다. @@ -130,7 +130,7 @@ product 들의 원본 목록은 props를 통해서 전달되기 때문에, state ## 5단계: 반대방향 자료 흐름을 추가하세요. - + 앞서 우리는 계층적으로 아랫방향 흐름의 props, state전달로 잘 동작하는 애플리케이션을 만들었습니다. 이제 다른방향의 자료 흐름을 지원할 시간입니다: form 컴포넌트들은 `FilterableProductTable`의 state를 업데이트할 필요성이 있죠. diff --git a/docs/thinking-in-react.md b/docs/thinking-in-react.md index 922907da..bdaf5ad3 100644 --- a/docs/thinking-in-react.md +++ b/docs/thinking-in-react.md @@ -61,7 +61,7 @@ Now that we've identified the components in our mock, let's arrange them into a ## Step 2: Build a static version in React - + Now that you have your component hierarchy, it's time to implement your app. The easiest way is to build a version that takes your data model and renders the UI but has no interactivity. It's best to decouple these processes because building a static version requires a lot of typing and no thinking, and adding interactivity requires a lot of thinking and not a lot of typing. We'll see why. @@ -105,7 +105,7 @@ So finally, our state is: ## Step 4: Identify where your state should live - + OK, so we've identified what the minimal set of app state is. Next, we need to identify which component mutates, or *owns*, this state. @@ -130,7 +130,7 @@ You can start seeing how your application will behave: set `filterText` to `"bal ## Step 5: Add inverse data flow - + So far, we've built an app that renders correctly as a function of props and state flowing down the hierarchy. Now it's time to support data flowing the other way: the form components deep in the hierarchy need to update the state in `FilterableProductTable`. diff --git a/docs/thinking-in-react.zh-CN.md b/docs/thinking-in-react.zh-CN.md index e8fd2836..43cf1147 100644 --- a/docs/thinking-in-react.zh-CN.md +++ b/docs/thinking-in-react.zh-CN.md @@ -8,13 +8,13 @@ redirect_from: 'blog/2013/11/05/thinking-in-react.html' by Pete Hunt -在我看来,React 是构建大型,快速 web app 的首选方式。它已经在 Facebook 和 Instagram 被我们有了广泛的应用。 +在我看来,React 是构建大型,快速 Web app 的首选方式。它已经在 Facebook 和 Instagram 被我们有了广泛的应用。 -React许多优秀的部分之一是它如何使你随着构建 app 来思考 app。在本文里,我将带领你学习一个用 React 构建可搜索的数据表的思考过程。 +React 许多优秀的部分之一,是它使得你在构建 app 的过程中不断思考。在本文里,我将带你经历一次使用 React 构建可搜索的商品数据表的思考过程。 ## 从模型(mock)开始 -想象我们已经有个一个 JSON API 和一个来自设计师的模型。我们的设计师似乎不是很好因为模型看起来像是这样: +想象我们已经有个一个 JSON API 和一个来自设计师的模型。我们的设计师显然做得不够好,因为模型看起来像这样: ![Mockup](/react/img/blog/thinking-in-react-mock.png) @@ -33,25 +33,25 @@ React许多优秀的部分之一是它如何使你随着构建 app 来思考 app ## 第一步:把UI拆分为一个组件的层级 -首先你想要做的是在模型里的每一个组建周围绘制边框并给他们命名。如果你和设计师一起工作,他们应该已经完成这步了,所以去和他们谈谈!他们的photoshop图层名也许最终会成为你的React组件名。 +首先你想要做的,是在模型里的每一个组件周围绘制边框,并给它们命名。如果你和设计师一起工作,他们应该已经完成这步了,所以去和他们谈谈!他们的 Photoshop 图层名也许最终会成为你的 React 组件名。 -但是你如何知道什么东西应该是独立的组件?只需使用你决定是否创建一个函数或者对象的相同技术。这样一种技术是[single responsibility principle](https://en.wikipedia.org/wiki/Single_responsibility_principle),即是,一个组件在理想情况下只做一件事情。如果它最终变大,它就应该被分解为更小的组件。 +但是你如何知道什么东西应该是独立的组件?只需在你创建一个函数或者对象时,根据是否使用过相同技术来做决定。一种这样的技术是[单一功能原则(single responsibility principle)](https://en.wikipedia.org/wiki/Single_responsibility_principle),也就是一个组件在理想情况下只做一件事情。如果它最终增长了,它就应该被分解为更小的组件。 -既然你频繁显示一个JSON的数据模型给用户,你会发现,如果你的模型构建正确,你的UI(因此也有你的组件结构)就将映射良好.那是因为UI和数据模型趋向于附着于相同的 *信息架构*,这意味着把你的 UI 分离为组件的工作通常是简单的,只需把他拆成精确对应代表你的数据模型的每一块的组件. +既然你频繁显示一个 JSON 的数据模型给用户,你会发现,如果你的模型构建正确,你的 UI(因此也有你的组件结构)就将映射良好。那是因为 UI 和数据模型趋向附着于相同的 *信息架构*,这意味着,把你的 UI 分离为组件的工作通常是琐碎的,只需把 UI 拆分成能准确对应数据模型的每块组件。 ![Component diagram](/react/img/blog/thinking-in-react-components.png) -在这里你会看到,在我们简单的APP里有五个组件.我用斜体表示每个组件的数据. +在这里你会看到,在我们的简单 APP 里有五个组件。我用斜体表示每个组件的数据。 - 1. **`FilterableProductTable` (orange):** 包含示例的整体 - 2. **`SearchBar` (blue):** 接受所有 *用户输入* - 3. **`ProductTable` (green):** 基于 *用户输入* 显示和过滤 *数据集合(data collection)* - 4. **`ProductCategoryRow` (turquoise):** 为每个 *分类* 显示一个列表头 - 5. **`ProductRow` (red):** 为每个 *产品* 显示一个行 + 1. **`FilterableProductTable` (橙色):** 包含示例的整体 + 2. **`SearchBar` (蓝色):** 接收所有 *用户输入* + 3. **`ProductTable` (绿色):** 基于 *用户输入* 显示和过滤 *数据集合(data collection)* + 4. **`ProductCategoryRow` (蓝绿色):** 为每个 *分类* 显示一个列表头 + 5. **`ProductRow` (红色):** 为每个 *商品* 显示一行 -如果你看着 `ProductTable`,你会看到表的头(包含了 "Name" 和 "Price" 标签) 不是独立的组件.这是一个个人喜好问题,并且无论哪种方式都有争论.对于这个例子,我把它留做 `ProductTable` 的一部分,因为它是 *data collection*渲染的一部分,而 *data collection*渲染是 `ProductTable` 的职责.然而,当列表头增长到复杂的时候(例如 如果我们添加排序的功能性),那么无疑的使它成为独立的 `ProductTableHeader` 组件是有意义的. +如果你看着 `ProductTable`,你会看到表头(包含了 "Name" 和 "Price" 标签) 不是独立的组件。这是一个个人喜好问题,并且无论采用哪种方式都有争论。对于这个例子,我把它留做 `ProductTable` 的一部分,因为它是 *data collection*渲染的一部分,而 *data collection* 渲染是 `ProductTable` 的职责。然而,当列表头增长到复杂的时候(例如 如果我们添加排序功能),那么使它成为独立的 `ProductTableHeader` 组件无疑是有意义的。 -既然现在我们已经识别出了我们模型中的组件,让我们把他们安排到一个层级中.这很容易. 在模型中出现在其他组件中的组件 同样应该在层级中表现为一个子级: +既然现在我们已经识别出了我们模型中的组件,让我们把他们安排到一个层级中。这很容易。在模型中,出现在一个组件里面的另一组件 ,应该在层级中表现为一种子级关系: * `FilterableProductTable` * `SearchBar` @@ -59,89 +59,89 @@ React许多优秀的部分之一是它如何使你随着构建 app 来思考 app * `ProductCategoryRow` * `ProductRow` -## Step 2: 用React创建一个静态版本 +## 第二步:用React创建一个静态版本 - + -既然你已经有了你的组件层级,时候实现你的app了.简单的方式是构建一个版本,它采取你的数据模型并渲染UI但是没有互动性.最好是分离这些过程,因为构建一个静态版本需要无脑的打很多字,然而添加互动性需要很多思考但不需要打太多字.我们会看到是为什么: +既然你已经有了你的组件层级,是时候实现你的app了。简单的方式是构建一个版本,它取走你的数据模型并渲染UI,除了没有互动性。这是将过程解耦的最好办法,因为构建一个静态版本需要不假思索地写很多代码,而添加互动性需要很多思考但不需要太多代码。之后我们将会看到原因。 -要构建一个渲染你的数据模型的 app 的静态版本,你会想构建一个重用其他组件并利用 *props* 传递数据的组件. *props* 是一种从父级传递数据到子级的方式.如果你对 *state* 的观念很熟悉, **绝不要用state** 来构建这个静态版本.State 仅仅是为互动预留的,即,随时间变化的数据. 因为这是一个静态版本的app,你不需要它. +要构建一个静态版本 app 来渲染你的数据模型,你将会想到构建一个重用其它组件并利用 *props* 传递数据的组件。*props* 是一种从父级传递数据到子级的方式。如果你对 *state* 的观念很熟悉,**绝不要用state** 来构建这个静态版本。State 仅仅是为互动性,也就是随时间变化的数据所预留的。由于这是一个静态版本,你还不需要用到它。 -你可以自顶向下或自底向上的构建.也就是说,你可以既从较高的层级(如 从 `FilterableProductTable` 开始) 也可以从较低的层级(`ProductRow`)开始构建组件. 在较简单的例子里,通常自顶向下要容易一些,然而在更大的项目上 自底向上更容易,并且伴随着构建写测试较容易. +你可以自顶向下或自底向上的构建。也就是说,你可以既从较高的层级(比如从 `FilterableProductTable` 开始)也可以从较低的层级(`ProductRow`)开始构建组件。在较简单的例子里,通常自顶向下要容易一些,然而在更大的项目上,自底向上地构建更容易,并且更方便伴随着构建写测试。 -在这一步的最后,你会有一个渲染你数据模型的可重用的组件库. 这些组件将只含有 `render()` 方法因为这是一个你的app的静态版本. 在层级顶端的组件 (`FilterableProductTable`) 将会接受你的数据模型作为一个prop.如果你对你的底层数据模型做了变化并且再次调用 `ReactDOM.render()` ,UI将会更新.很容易看到你的UI是如何更新以及哪里来作出变动,因为这里没有任何复杂的事情发生. React的 **单向数据流** (也被称为 *单向绑定* )保持了每个东西模块化和快速. +在这一步的最后,你会获得一个渲染数据模型的可重用组件库。这些组件只有 `render()` 方法,因为这是一个静态版本。在层级顶端的组件 (`FilterableProductTable`) 将会接受你的数据模型,并将其作为一个prop。如果你改变了底层数据模型,并且再次调用 `React.render()` ,UI 将会更新。你可以很容易地看到 UI 是如何更新的,以及哪里变动了,因为这没什么复杂的。React的 **单向数据流** (也被称为 *单向绑定*)使一切保持了模块化和快速。 -如果你执行这步需要帮助,请参考 [React docs](/react/docs/) . +如果你在执行这步时需要帮助,请参阅 [React 文档](/react/docs/)。 ### 小插曲: props vs state -在React里有两种数据 "模型":props和state.明白这二者之间的区别是很重要的;如果你不是很确定不同是什么,请概览[React官方文档](/react/docs/interactivity-and-dynamic-uis-zh-CN.html) +在React里有两种数据 "模型": props 和 state。明白这二者之间的区别是很重要的;如果你不是很确定它们之间的区别,请概览[React官方文档](/react/docs/interactivity-and-dynamic-uis-zh-CN.html) -## 第三步:确定最小(但完备)的 UI state 的表达 +## 第三步:确定最小(但完备)的 UI state 表达 -要让你的UI互动,你需要能够触发变化到你的底层数据模型上.React用 **state** 来让此变得容易. +要让你的 UI 互动,你需要做到触发底层数据模型发生变化。React用 **state** 来让此变得容易。 -要正确的构建你的app,你首先需要思考你的app需要的可变state的最小组. 这里的关键是 DRY: *Don't Repeat Yourself(不要重复自己)*.想出哪些是你的应用需要的绝对最小 state 表达,并按需计算其他任何数据.例如,如果你要构建一个 TODO list,只要保持一个 TODO 项的数组;不要为了计数保持一个单独的 state 变量.作为替代,当你想渲染 TODO 数量时,简单的采用TODO项目数组的长度. +要正确的构建你的 app,你首先需要思考你的 app 需要的可变 state 的最小组。这里的关键是 DRY 原则:*Don't Repeat Yourself(不要重复自己)*。想出哪些是你的应用需要的绝对最小 state 表达,并按需计算其他任何数据。例如,如果你要构建一个 TODO list,只要保持一个 TODO 项的数组;不要为了计数保持一个单独的 state 变量。当你想渲染 TODO 的计数时,简单的采用 TODO 项目的数组长度作为替代。 -考虑我们例子应用中数据的所有块.我们有: +考虑我们示例应用中的数据所有块,包括: - * 原始的产品列表 + * 原始的商品列表 * 用户输入的搜索文本 - * checkbox的值 - * 产品的滤过的列表 + * 复选框的值 + * 商品的过滤列表 -让我们遍历每一个并指出哪一个是state.简单的问三个关于每个数据块的问题: +让我们逐个检查出哪一个是state,只需要简单地问以下三个问题: - 1. 它是通过props从父级传递来的吗?如果是,它可能不是state. - 2. 它随时间变化吗?如果不是,它可能不是state. - 3. 你能基于其他任何组件里的 state 或者 props 计算出它吗?如果是,它可能不是state. + 1. 它是通过props从父级传递来的吗?如果是,它可能不是 state。 + 2. 它随时间变化吗?如果不是,它可能不是 state。 + 3. 你能基于其他任何组件里的 state 或者 props 计算出它吗?如果是,它可能不是state. -原始的产品列表被以 props 传入,所以它不是 state. 搜索文本和 checkbox 看起来是state 因为他们随时间变化并且不能从任何东西计算出.最后,产品滤过的列表不是state因为它可以联合原始列表与搜索文本及 checkbox 的值计算出. +原始的商品列表以 props 传入,所以它不是 state。搜索文本和复选框看起来是 state,因为他们随时间变化并且不能从任何东西计算出。最后,过滤出的商品列表不是 state,因为它可以通过原始列表与搜索文本及复选框的值组合计算得出。 所以最后,我们的 state 是: * 用户输入的搜索文本 * checkbox 的值 -## 第四步:确定你的 state 应该存在于哪里 +## 第四步:确定你的 state 应该存在于哪里 - + -好,我们已经确定了app state 的最小组是什么.接下来,我们需要确定哪个组件变动,或者 *拥有*,这 个state. +OK,我们已经确定好应用的最小 state 集合是什么。接下来,我们需要确定哪个组件可以改变,或者 *拥有* 这个state. -记住:React都是关于单向数据流下组件层级的.可能不能立刻明白哪些组件应该拥有哪些 state. **这常常对于新手在理解上是最具挑战的一部分,** 所以跟着这几步来弄明白它: +记住:React 总是在组件层级中单向数据流动的。可能不能立刻明白哪些组件应该拥有哪些 state。 **这对于新手在理解上经常是最具挑战的一部分,** 所以跟着这几步来弄明白它: -对于你的应用里每一个数据块: +对于你的应用里每一个数据块: - * 基于 state 确定每个绘制某些东西的组件 - * 找到一个共同拥有者的组件(在层级中所有组件之上需要这个state的单个组件) - * 要么是共同拥有者,要么是其他在层级里更高级的组件应该拥有这个state - * 如果你不能找到一个组件,它拥有这个state有意义,创建一个新的组件简单的为了持有此state,并把它在层级里添加比共同拥有者组件更高的层级上. + * 确定哪些组件要基于 state 来渲染内容。 + * 找到一个共同的拥有者组件(在所有需要这个state组件的层次之上,找出共有的单一组件)。 + * 要么是共同拥有者,要么是其他在层级里更高级的组件应该拥有这个state。 + * 如果你不能找到一个组件让其可以有意义地拥有这个 state,可以简单地创建一个新的组件 hold 住这个state,并把它添加到比共同拥有者组件更高的层级上。 -让我们过一遍这个用于我们应用的策略: +让我们使用这个策略浏览一遍我们的应用: - * `ProductTable` 需要基于 state 过滤产品列表,`SearchBar` 需要显示搜索文本和选择状态. - * 共同拥有者组件是`FilterableProductTable` . - * 对于过滤文本和选择值存在于 `FilterableProductTable` 观念上是有意义的. + * `ProductTable` 需要基于 state 过滤产品列表,`SearchBar` 需要显示搜索文本和选择状态。 + * 共同拥有者组件是 `FilterableProductTable`。 + * 对于过滤文本和选择框值存在于 `FilterableProductTable`,从概念上讲是有意义的。 -酷,我们已经决定了我们的state存在于 `FilterableProductTable` .首先,添加一个 `getInitialState()` 方法到 `FilterableProductTable` ,返回 `{filterText: '', inStockOnly: false}` 来反映你的应用的初始状态. 然后,传递`filterText` 和 `inStockOnly` 给 `ProductTable` 和`SearchBar` 作为prop.最后,使用这些prop来过滤 `ProductTable` 中的行和设置`SearchBar`的表单项的值. +酷,我们已经决定了我们的 state 存在于 `FilterableProductTable`。首先,添加一个 `getInitialState()` 方法到 `FilterableProductTable`,返回 `{filterText: '', inStockOnly: false}` 来反映应用的初始状态。然后,传递`filterText` 和 `inStockOnly` 给 `ProductTable` 和 `SearchBar` 作为 prop。最后,使用这些 prop 来过滤 `ProductTable` 中的行和设置 `SearchBar` 的表单项的值。 -你可以开始看看你的应用将有怎样的行为: 设置 `filterText` 为 `"ball"` 并刷新你的app.你将看到数据表被正确更新了. +你可以开始看看你的应用将有怎样的行为了: 设置 `filterText` 为 `"ball"` 并刷新你的 app。你将可以看到数据表被正确地更新。 -## 第五步:添加反向数据流 +## 第五步:添加反向数据流 - + -到目前为止,我们已经构建了一个应用, 它以props 和 state 沿着层级向下流动的功能正确渲染。现在是时候支持数据的另一种流动了:在层级深处的表单组件需要更新 `FilterableProductTable` 里的state. +到目前为止,我们已经构建了一个应用, 它以 props 和 state 沿着层级向下流动的功能正确渲染。现在是时候支持另一种数据流动了:在层级深处的表单组件需要更新 `FilterableProductTable` 里的 state。 -React 让数据显式流动,使理解你的应用如何工作变得简单,但是相对于传统的双向数据绑定,确实需要打多一些的字。 React 提供了一个叫做 `ReactLink` 的插件来使这种模式和双向数据绑定一样方便,但是考虑到这篇文章的目的,我们将会保持所有东西都直截了当。 +React 让数据显式流动,使你理解应用如何工作变得简单,但是相对于传统的双向数据绑定,确实需要多打一些字。React 提供了一个叫做 `ReactLink` 的插件来使这种模式和双向数据绑定一样方便,但是考虑到这篇文章的目的,我们将会保持所有东西都直截了当。 -如果你尝试在当前版本的示例中输入或者选中复选框,你会发现 React 忽略了你的输入。这是有意的,因为已经设置了 `input` 的 `value` prop 总是与 `FilterableProductTable` 传递过来的 `state` 一致。 +如果你尝试在当前版本的示例中输入或者选中复选框,你会发现 React 忽略了你的输入。这是有意的,因为我们已经设置了 `input` 的 `value` prop 值总是与 `FilterableProductTable` 传递过来的 `state` 一致。 -让我们思考下我们希望发生什么。我们想确保每当用户改变了表单,我们就更新 state 来反映用户的输入。由于组件应该只更新自己拥有的 state , `FilterableProductTable` 将会传递一个回调函数给 `SearchBar` ,此函数每当 state 应被改变时就会击发。我们可以使用 input 的 `onChange` 事件来接受它的通知。 `FilterableProductTable` 传递的回调函数将会调用 `setState()` ,然后应用将会被更新。 +让我们思考下希望发生什么。我们想确保每当用户改变表单,就通过更新 state 来反映用户的输入。由于组件应该只更新自己拥有的 state , `FilterableProductTable` 将会传递一个回调函数给 `SearchBar` ,每当 state 应被更新时回调函数就会被调用。我们可以使用 input 的 `onChange` 事件来接受它的通知。 `FilterableProductTable` 传递的回调函数将会调用 `setState()` ,然后应用将会被更新。 -虽然这听起来复杂,但是实际上只是数行代码。并且数据在应用中从始至终如何流动是非常明确的。 +虽然这听起来复杂,但是实际上只是数行代码。并且这明确显示出了数据在应用中从始至终是如何流动的。 -## 好了,就是这样 +## 好了,就是这样 -希望,这给了你一个怎样思考用React构建组件和应用的概念。虽然可能比你通常要输入更多的代码,记住,读代码的时间远比写代码的时间多,并且阅读这种模块化的,显式的代码是极端容易的。当你开始构建大型组件库时,你会非常感激这种清晰性和模块化,并且随着代码的重用,你的代码行数将会开始缩减. :)。 +希望这给了你一个怎样思考用React构建组件和应用的概念。虽然可能比你过往的习惯要多敲一点代码,但记住,读代码的时间远比写代码的时间多,并且阅读这种模块化的、显式的代码是极为容易的。当你开始构建大型组件库时,你会非常感激这种清晰性和模块化,并且随着代码的重用,你的代码行数将会开始缩减。:) diff --git a/downloads/react-0.14.4.zip b/downloads/react-0.14.4.zip new file mode 100644 index 00000000..d17ffcd1 Binary files /dev/null and b/downloads/react-0.14.4.zip differ diff --git a/downloads/react-0.14.5.zip b/downloads/react-0.14.5.zip new file mode 100644 index 00000000..b241cb24 Binary files /dev/null and b/downloads/react-0.14.5.zip differ diff --git a/downloads/react-0.14.6.zip b/downloads/react-0.14.6.zip new file mode 100644 index 00000000..38fbd33d Binary files /dev/null and b/downloads/react-0.14.6.zip differ diff --git a/img/docs/should-component-update.png b/img/docs/should-component-update.png index ac268270..b9821c00 100644 Binary files a/img/docs/should-component-update.png and b/img/docs/should-component-update.png differ diff --git a/js/react-dom.js b/js/react-dom.js index 02299f15..7a4c0940 100644 --- a/js/react-dom.js +++ b/js/react-dom.js @@ -1,5 +1,5 @@ /** - * ReactDOM v0.14.3 + * ReactDOM v0.14.6 * * Copyright 2013-2015, Facebook, Inc. * All rights reserved. diff --git a/js/react.js b/js/react.js index 24108cb5..d394d541 100644 --- a/js/react.js +++ b/js/react.js @@ -1,5 +1,5 @@ /** - * React v0.14.3 + * React v0.14.6 */ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.React = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o > This isn't really a React-specific tip, as such anti-patterns often occur in code in general; in this case, React simply points them out more clearly. -Using props, passed down from parent, to generate state in `getInitialState` often leads to duplication of "source of truth", i.e. where the real data is. Whenever possible, compute values on-the-fly to ensure that they don't get out of sync later on and cause maintenance trouble. +Using props to generate state in `getInitialState` often leads to duplication of "source of truth", i.e. where the real data is. This is because `getInitialState` is only invoked when the component is first created. + +Whenever possible, compute values on-the-fly to ensure that they don't get out of sync later on and cause maintenance trouble. **Bad example:** @@ -43,7 +45,7 @@ ReactDOM.render(, mountNode); (For more complex logic, simply isolate the computation in a method.) -However, it's **not** an anti-pattern if you make it clear that synchronization's not the goal here: +However, it's **not** an anti-pattern if you make it clear that the prop is only seed data for the component's internally-controlled state: ```js var Counter = React.createClass({ diff --git a/tips/18-use-react-with-other-libraries.ko-KR.md b/tips/18-use-react-with-other-libraries.ko-KR.md index d0ec83e9..9dfd1d46 100644 --- a/tips/18-use-react-with-other-libraries.ko-KR.md +++ b/tips/18-use-react-with-other-libraries.ko-KR.md @@ -16,7 +16,7 @@ var App = React.createClass({ }, componentDidMount: function() { - $(ReactDOM.findDOMNode(this.refs.placeholder)).append($('')); + $(this.refs.placeholder).append($('')); }, componentWillUnmount: function() { diff --git a/tips/18-use-react-with-other-libraries.md b/tips/18-use-react-with-other-libraries.md index f7bb2cb3..fc5634fa 100644 --- a/tips/18-use-react-with-other-libraries.md +++ b/tips/18-use-react-with-other-libraries.md @@ -16,7 +16,7 @@ var App = React.createClass({ }, componentDidMount: function() { - $(ReactDOM.findDOMNode(this.refs.placeholder)).append($('')); + $(this.refs.placeholder).append($('')); }, componentWillUnmount: function() {