diff --git a/docs/08.1-more-about-refs.zh-CN.md b/docs/08.1-more-about-refs.zh-CN.md index 149c6c7f9..65cba54a3 100644 --- a/docs/08.1-more-about-refs.zh-CN.md +++ b/docs/08.1-more-about-refs.zh-CN.md @@ -170,5 +170,5 @@ Refs是一种很好的发送消息给特定子实例(通过流式的Reactive `pr - *绝不* 在任何组件的 render 方法中访问 refs - 或者当任何组件的render方法还在调用栈上的任何地方运行时。 - 如果你想要保留Google Closure Compiler Crushing resilience,务必不要把指明为字符串的以属性来访问。这意味这你必须用`this.refs['myRefString']`访问,如果你的ref被定义为`ref="myRefString"`。 -- 如果你没有用React写过数个程序,你的第一反应通常是打算试着用refs来在你的应用里"让事情发生"。如果是这样,花一些时间并且更精密的思考`state`应该属于组件层级的哪个位置。常常,这会变得清晰:正确的"拥有"那个属性的地方应该在层级的更高层上。把state放在那里往往消除了任何使用`ref`来 "让事情发生"的渴望 - 作为替代,数据流通常将完成你的目录。 +- 如果你没有用React写过数个程序,你的第一反应通常是打算试着用refs来在你的应用里"让事情发生"。如果是这样,花一些时间并且更精密的思考`state`应该属于组件层级的哪个位置。常常,这会变得清晰:正确的"拥有"那个属性的地方应该在层级的更高层上。把state放在那里往往消除了任何使用`ref`来 "让事情发生"的渴望 - 作为替代,数据流通常将完成你的目标。 diff --git a/docs/ref-01-top-level-api.zh-CN.md b/docs/ref-01-top-level-api.zh-CN.md new file mode 100644 index 000000000..eb45c81cc --- /dev/null +++ b/docs/ref-01-top-level-api.zh-CN.md @@ -0,0 +1,191 @@ +--- +id: top-level-api-zh-CN +title: Top-Level API +permalink: top-level-api-zh-CN.html +next: component-api-zh-CN.html +redirect_from: "/docs/reference-zh-CN.html" +--- + +## React + +`React` 是 React 库的入口点。如果你使用预编译包中的一个,则 `React` 为全局变量;如果你使用 CommonJS 模块,你可以 `require()` 它。 + + +### React.Component + +```javascript +class Component +``` + +当使用ES6 类定义时,React.Component是 React 组件的基类。如何在React中使用 ES6 class 请参见 [可重用组件](/react/docs/reusable-components-zh-CN.html#es6-classes)。基类实际提供了哪些方法 请参见 [组件 API](/react/docs/component-api-zh-CN.html). + + +### React.createClass + +```javascript +ReactClass createClass(object specification) +``` + +给定一份规格(specification),创建一个组件类。组件通常要实现一个 `render()` 方法,它返回 **单个的** 子级。该子级可能包含任意深度的子级结构。组件与标准原型类的不同之处在于,你不需要对它们调用 new。 它们是为你在后台构造实例(通过 new)的便利的包装器。 + +更多关于规格对象(specification object)的信息,请见 [组件规格和生命周期](/react/docs/component-specs-zh-CN.html) 。 + + +### React.createElement + +```javascript +ReactElement createElement( + string/ReactClass type, + [object props], + [children ...] +) +``` + +创建并返回一个新的给定类型的 `ReactElement`。type 参数既可以是一个 html 标签名字符串(例如. “div”,“span”,等等),也可以是一个 `ReactClass` (用 `React.createClass` 创建的)。 + + + +### React.cloneElement + +``` +ReactElement cloneElement( + ReactElement element, + [object props], + [children ...] +) +``` + +使用 `element` 作为起点,克隆并返回一个新的 `ReactElement` 。生成的 element 将会拥有原始 element 的 props 与新的 props 的浅合并。新的子级将会替换现存的子级。 不同于 `React.addons.cloneWithProps`,来自原始 element 的 `key` 和 `ref` 将会保留。对于合并任何 props 没有特别的行为(不同于 `cloneWithProps`)。更多细节详见[v0.13 RC2 blog post](/react/blog/2015/03/03/react-v0.13-rc2.html) 。 + + +### React.createFactory + +```javascript +factoryFunction createFactory( + string/ReactClass type +) +``` + +返回一个生成给定类型的 ReactElements 的函数。如同 `React.createElement`,type 参数既可以是一个 html 标签名字符串(例如. “div”,“span”,等等),也可以是一个 `ReactClass` 。 + + + + +### React.render + +```javascript +ReactComponent render( + ReactElement element, + DOMElement container, + [function callback] +) +``` + +渲染一个 ReactElement 到 DOM 里提供的 `容器(container)`中,并返回一个对组件的引用。 + +如果 ReactElement 之前被渲染到了 `container` 中,这将对它执行一次更新,并仅变动需要变动的 DOM 来反映最新的 React 组件。 + +如果提供了可选的回调函数,则该函数将会在组件渲染或者更新之后被执行。 + +> 注意: +> +> `React.render()` 控制你传入的 container 节点的内容。 +> 当初次调用时,任何现存于内的 DOM 元素将被替换。 +> 其后的调用使用 React的 diffing 算法来有效率的更新。 +> +> `React.render()` 不会修改 container 节点(只修改 container 的子级)。 +> 将来,也许能够直接插入一个组件到已经存在的 DOM 节点而不覆盖 +> 现有的子级。 + + +### React.unmountComponentAtNode + +```javascript +boolean unmountComponentAtNode(DOMElement container) +``` + +从 DOM 中移除已经挂载的 React 组件,并清除它的事件处理器和 state。如果在 container 中没有组件被挂载,调用此函数将什么都不做。如果组件被卸载返回 `true`,如果没有组件被卸载返回 `false`。 + + +### React.renderToString + +```javascript +string renderToString(ReactElement element) +``` + +把 ReactElement 渲染为它原始的 HTML 。这应该仅在服务器端使用。React 将会返回一个 HTML 字符串。你可以用这种方法在服务器端生成 HTML,然后在初始请求下传这些标记,以获得更快的页面加载速度及允许搜索引擎抓取页面(便于 SEO)。 + +如果在一个在已经有了这种服务器预渲染标记的节点上面调用 `React.render()`,React 将会维护该节点,仅绑定事件处理器,让你有一个非常高效的初次加载体验。 + + +### React.renderToStaticMarkup + +```javascript +string renderToStaticMarkup(ReactElement element) +``` + +类似于 `renderToString` ,除了不创建额外的 DOM 属性,比如 `data-react-id`,这仅在 React 内部使用的属性。如果你想用 React 做一个简单的静态页面生成器,这是很有用的,因为去除额外的属性能够节省很多字节。 + + +### React.isValidElement + +```javascript +boolean isValidElement(* object) +``` + +验证对象是否是一个 ReactElement。 + + +### React.findDOMNode + +```javascript +DOMElement findDOMNode(ReactComponent component) +``` +如果这个组件已经被挂载到了 DOM,它返回相应的浏览器原生的 DOM 元素。这个方法对于读取 DOM 的值很有用,比如表单域的值和执行 DOM 的测量。如果 `render` 返回 `null` 或者 `false`, `findDOMNode` 返回 `null`. + + +### React.DOM + +`React.DOM` 用 `React.createElement` 为 DOM 组件提供了便利的包装器。该方式应该只在不使用 JSX 的时使用。例如,`React.DOM.div(null, 'Hello World!')`。 + + +### React.PropTypes + +`React.PropTypes` 包含了能与 组件的`propTypes` 对象一起使用的类型,用以验证传入你的组件的 props。更多有关 `propTypes` 的信息,请见 [可重用组件](/react/docs/reusable-components-zh-CN.html)。 + + +### React.Children + +`React.Children` 为处理 `this.props.children` 这个不透明的数据结构提供了工具。 + +#### React.Children.map + +```javascript +object React.Children.map(object children, function fn [, object thisArg]) +``` + +在每一个包含在 `children` 中的直接子级上调用 `fn` ,`fn`中的 `this` 设置为 `thisArg`。如果 `children` 是一个嵌套的对象或者数组,它将被遍历:不会传入容器对象到 `fn` 中。如果 children 是 `null` 或者 `undefined`,则返回 `null` 或者 `undefined` 而不是一个空对象。 + +#### React.Children.forEach + +```javascript +React.Children.forEach(object children, function fn [, object thisArg]) +``` + +类似 `React.Children.map()`,但是不返回对象。 + +#### React.Children.count + +```javascript +number React.Children.count(object children) +``` + +返回 `children` 中的组件总数,相等于传递给 `map` 或者 `forEach` 的回调函数应被调用次数。 + +#### React.Children.only + +```javascript +object React.Children.only(object children) +``` + +返回 `children` 中仅有的子级。否则抛出异常。 diff --git a/docs/ref-02-component-api.zh-CN.md b/docs/ref-02-component-api.zh-CN.md new file mode 100644 index 000000000..231e33cfa --- /dev/null +++ b/docs/ref-02-component-api.zh-CN.md @@ -0,0 +1,146 @@ +--- +id: component-api-zh-CN +title: 组件 API +permalink: component-api-zh-CN.html +prev: top-level-api-zh-CN.html +next: component-specs-zh-CN.html +--- + +## React.Component + +当渲染时,React 组件的实例在 React 内部被创建。这些实例在随后的渲染中被重复使用,并可以在组件方法中通过 `this` 访问。唯一的在 React 之外获取 React 组件实例句柄的方法是保存 `React.render` 的返回值。在其它组件内,你可以使用 [refs](/react/docs/more-about-refs-zh-CN.html) 得到相同的结果。 + + +### setState + +```javascript +setState( + function|object nextState, + [function callback] +) +``` +执行一个 nextState 到当前 state 的浅合并。这是你从事件处理器和服务器请求回调用来触发 UI 更新的主要手段。 + +第一个参数可以是一个对象(包含0或者多个keys来更新)或者一个(state 和 props的)函数,它返回一个包含要更新的keys的对象。 + +这里是一个简单的运用: + +```javascript +setState({mykey: 'my new value'}); +``` + +也可以以 `function(state, props)` 传递一个函数。当你想要把一个在设置任何值之前参考前一次 state+props 的值的原子更新放在队列中 这会有很用。例如,假如我们想在 state 增加一个值。 + +```javascript +setState(function(previousState, currentProps) { + return {myInteger: previousState.myInteger + 1}; +}); +``` + +第二个(可选)的参数是一个将会在 `setState` 完成和组件被重绘后执行的回调函数。 + +> 注意: +> +> *绝对不要* 直接改变 `this.state`,因为之后调用 `setState()` 可能会替换掉你做的改变。把 `this.state` 当做是不可变的。 +> +> `setState()` 不会立刻改变 `this.state`,而是创建一个即将处理的 state 转变。在调用该方法之后访问 `this.state` 可能会返回现有的值。 +> +> 对 `setState` 的调用没有任何同步性的保证,并且调用可能会为了性能收益批量执行。 +> +> `setState()` 将总是触发一次重绘,除非在 `shouldComponentUpdate()` 中实现了条件渲染逻辑。如果可变对象被使用了,但又不能在 `shouldComponentUpdate()` 中实现这种逻辑,仅在新 state 和之前的 state 存在差异的时候调用 `setState()` 可以避免不必要的重新渲染。 + + +### replaceState + +```javascript +replaceState( + object nextState, + [function callback] +) +``` + +类似于 `setState()`,但是删除任何 先前存在但不在 nextState 里的 state 键。 + +> 注意: +> +> 这个方法在从 `React.Component` 扩展的 ES6 `class` 组件里不可用。它也许会在未来的 React 版本中被完全移除。 + + +### forceUpdate + +```javascript +forceUpdate( + [function callback] +) +``` + +默认情况下,当你的组件的 state 或者 props 改变,你的组件将会重绘。然而,如果它们隐式的改变(例如:在对象深处的数据改变了但没有改变对象本身)或者如果你的 `render()` 方法依赖于其他的数据,你可以用调用 `forceUpdate()` 来告诉 React 它需要重新运行 `render()`。 + +调用 `forceUpdate()` 将会导致 `render()` 跳过 `shouldComponentUpdate()` 在组件上被调用,这会为子级触发正常的生命周期方法。包括每个子级的 `shouldComponentUpdate()` 方法。如果标记改变了,React 仍仅只更新 DOM。 + +通常你应该试着避免所有对 `forceUpdate()` 的使用并且在 `render()` 里只从 `this.props` 和 `this.state` 读取。这会使你的组件 "纯粹" 并且你的组件会更简单和高效。 + + +### getDOMNode + +```javascript +DOMElement getDOMNode() +``` + +如果这个组件已经被挂载到了 DOM,它返回相应的浏览器原生的 DOM 元素。这个方法对于读取 DOM 的值很有用,比如表单域的值和执行 DOM 的测量。如果 `render` 返回 `null` 或者 `false` 的时候,`this.getDOMNode()` 返回 `null`。 + +> Note: +> +> getDOMNode 被废弃了,已经被 [React.findDOMNode()] 替换(/react/docs/top-level-api-zh-CN.html#react.finddomnode). +> +> 这个方法在从 `React.Component` 扩展的 ES6 `class` 组件里不可用。它也许会在未来的 React 版本中被完全移除。 + + +### isMounted + +```javascript +bool isMounted() +``` + +如果组件渲染到了 DOM 中,`isMounted()` 返回 true,否则返回 `false`。可以使用该方法来控制对 `setState()` 和 `forceUpdate()` 的异步调用。 + +> 注意: +> +> 这个方法在从 `React.Component` 扩展的 ES6 `class` 组件里不可用。它也许会在未来的 React 版本中被完全移除。 + + +### setProps + +```javascript +setProps( + object nextProps, + [function callback] +) +``` + +当和一个外部的 JavaScript 应用整合的时候,你也许会想用 `React.render()` 给 React 组件标示一个改变。 + +在根组件上调用 `setProps()` 会改变他的属性并触发一次重绘。另外,你可以提供一个可选的回调函数,一旦 `setProps` 完成并且组件被重绘它就执行。 + +> 注意: +> +> 如果可能,上述的在同一个节点上再次调用 `React.render()` 的方法是优先替代的。它往往使更新更容易理解。(两种方法并没有显著的性能区别。) +> +> 这个方法仅能在根组件上被调用。也就是说,它仅在直接传给 `React.render()` 的组件上可用,在它的子级上不可用。如果你倾向于在子组件上使用 `setProps()`,不要利用响应式更新,而是当子组件在 `render()` 中创建的时候传入新的 prop 到子组件中。 +> +> 这个方法在从 `React.Component` 扩展的 ES6 `class` 组件里不可用。它也许会在未来的 React 版本中被完全移除。 + +### replaceProps + +```javascript +replaceProps( + object nextProps, + [function callback] +) +``` + +类似于 `setProps()`,但是删除任何先前存在的 props,而不是合并这两个对象。 + +> 注意: +> +> 这个方法在从 `React.Component` 扩展的 ES6 `class` 组件里不可用。它也许会在未来的 React 版本中被完全移除。 diff --git a/docs/thinking-in-react.zh-CN.md b/docs/thinking-in-react.zh-CN.md new file mode 100644 index 000000000..5b378d6d1 --- /dev/null +++ b/docs/thinking-in-react.zh-CN.md @@ -0,0 +1,147 @@ +--- +id: thinking-in-react-zh-CN +title: React 编程思想 +prev: tutorial-zh-CN.html +next: conferences-zh-CN.html +redirect_from: 'blog/2013/11/05/thinking-in-react.html' +--- + +by Pete Hunt + +在我看来,React 是构建大型,快速 web app 的首选方式。它已经在 Facebook 和 Instagram 被我们有了广泛的应用。 + +React许多优秀的部分之一是它如何使你随着构建 app 来思考 app。在本文里,我将带领你学习一个用 React 构建可搜索的数据表的思考过程。 + +## 从模型(mock)开始 + +想象我们已经有个一个 JSON API 和一个来自设计师的模型。我们的设计师似乎不是很好因为模型看起来像是这样: + + + +我们的 JSON API 返回一些看起来像这样的数据: + +``` +[ + {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"}, + {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"}, + {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"}, + {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"}, + {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"}, + {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"} +]; +``` + +## 第一步:把UI拆分为一个组件的层级 + +首先你想要做的是在模型里的每一个组建周围绘制边框并给他们命名。如果你和设计师一起工作,他们应该已经完成这步了,所以去和他们谈谈!他们的photoshop图层名也许最终会成为你的React组件名。 + +但是你如何知道什么东西应该是独立的组件?只需使用你决定是否创建一个函数或者对象的相同技术。这样一种技术是[single responsibility principle](https://en.wikipedia.org/wiki/Single_responsibility_principle),即是,一个组件在理想情况下只做一件事情。如果它最终变大,它就应该被分解为更小的组件。 + +既然你频繁显示一个JSON的数据模型给用户,你会发现,如果你的模型构建正确,你的UI(因此也有你的组件结构)就将映射良好.那是因为UI和数据模型趋向于附着于相同的 *信息架构*,这意味着把你的 UI 分离为组件的工作通常是简单的,只需把他拆成精确对应代表你的数据模型的每一块的组件. + + + +在这里你会看到,在我们简单的APP里有五个组件.我用斜体表示每个组件的数据. + + 1. **`FilterableProductTable` (orange):** 包含示例的整体 + 2. **`SearchBar` (blue):** 接受所有 *用户输入* + 3. **`ProductTable` (green):** 基于 *用户输入* 显示和过滤 *数据集合(data collection)* + 4. **`ProductCategoryRow` (turquoise):** 为每个 *分类* 显示一个列表头 + 5. **`ProductRow` (red):** 为每个 *产品* 显示一个行 + +如果你看着 `ProductTable`,你会看到表的头(包含了 "Name" 和 "Price" 标签) 不是独立的组件.这是一个个人喜好问题,并且无论哪种方式都有争论.对于这个例子,我把它留做 `ProductTable` 的一部分,因为它是 *data collection*渲染的一部分,而 *data collection*渲染是 `ProductTable` 的职责.然而,当列表头增长到复杂的时候(例如 如果我们添加排序的功能性),那么无疑的使它成为独立的 `ProductTableHeader` 组件是有意义的. + +既然现在我们已经识别出了我们模型中的组件,让我们把他们安排到一个层级中.这很容易. 在模型中出现在其他组件中的组件 同样应该在层级中表现为一个子级: + + * `FilterableProductTable` + * `SearchBar` + * `ProductTable` + * `ProductCategoryRow` + * `ProductRow` + +## Step 2: 用React创建一个静态版本 + + + +既然你已经有了你的组件层级,时候实现你的app了.简单的方式是构建一个版本,它采取你的数据模型并渲染UI但是没有互动性.最好是分离这些过程,因为构建一个静态版本需要无脑的打很多字,然而添加互动性需要很多思考但不需要打太多字.我们会看到是为什么: + +要构建一个渲染你的数据模型的 app 的静态版本,你会想构建一个重用其他组件并利用 *props* 传递数据的组件. *props* 是一种从父级传递数据到子级的方式.如果你对 *state* 的观念很熟悉, **绝不要用state** 来构建这个静态版本.State 仅仅是为互动预留的,即,随时间变化的数据. 因为这是一个静态版本的app,你不需要它. + +你可以自顶向下或自底向上的构建.也就是说,你可以既从较高的层级(如 从 `FilterableProductTable` 开始) 也可以从较低的层级(`ProductRow`)开始构建组件. 在较简单的例子里,通常自顶向下要容易一些,然而在更大的项目上 自底向上更容易,并且伴随着构建写测试较容易. + +在这一步的最后,你会有一个渲染你数据模型的可重用的组件库. 这些组件将只含有 `render()` 方法因为这是一个你的app的静态版本. 在层级顶端的组件 (`FilterableProductTable`) 将会接受你的数据模型作为一个prop.如果你对你的底层数据模型做了变化并且再次调用 `React.render()` ,UI将会更新.很容易看到你的UI是如何更新以及哪里来作出变动,因为这里没有任何复杂的事情发生. React的 **单向数据流** (也被称为 *单向绑定* )保持了每个东西模块化和快速. + +如果你执行这步需要帮助,请参考 [React docs](/react/docs/) . + +### 小插曲: props vs state + +在React里有两种数据 "模型":props和state.明白这二者之间的区别是很重要的;如果你不是很确定不同是什么,请概览[React官方文档](/react/docs/interactivity-and-dynamic-uis-zh-CN.html) + +## 第三步:确定最小(但完备)的 UI state 的表达 + +要让你的UI互动,你需要能够触发变化到你的底层数据模型上.React用 **state** 来让此变得容易. + +要正确的构建你的app,你首先需要思考你的app需要的可变state的最小组. 这里的关键是 DRY: *Don't Repeat Yourself(不要重复自己)*.想出哪些是你的应用需要的绝对最小 state 表达,并按需计算其他任何数据.例如,如果你要构建一个 TODO list,只要保持一个 TODO 项的数组;不要为了计数保持一个单独的 state 变量.作为替代,当你想渲染 TODO 数量时,简单的采用TODO项目数组的长度. + +考虑我们例子应用中数据的所有块.我们有: + + * 原始的产品列表 + * 用户输入的搜索文本 + * checkbox的值 + * 产品的滤过的列表 + +让我们遍历每一个并指出哪一个是state.简单的问三个关于每个数据块的问题: + + 1. 它是通过props从父级传递来的吗?如果是,它可能不是state. + 2. 它随时间变化吗?如果不是,它可能不是state. + 3. 你能基于其他任何组件里的 state 或者 props 计算出它吗?如果是,它可能不是state. + +原始的产品列表被以 props 传入,所以它不是 state. 搜索文本和 checkbox 看起来是state 因为他们随时间变化并且不能从任何东西计算出.最后,产品滤过的列表不是state因为它可以联合原始列表与搜索文本及 checkbox 的值计算出. + +所以最后,我们的 state 是: + + * 用户输入的搜索文本 + * checkbox 的值 + +## 第四步:确定你的 state 应该存在于哪里 + + + +好,我们已经确定了app state 的最小组是什么.接下来,我们需要确定哪个组件变动,或者 *拥有*,这 个state. + +记住:React都是关于单向数据流下组件层级的.可能不能立刻明白哪些组件应该拥有哪些 state. **这常常对于新手在理解上是最具挑战的一部分,** 所以跟着这几步来弄明白它: + +对于你的应用里每一个数据块: + + * 基于 state 确定每个绘制某些东西的组件 + * 找到一个共同拥有者的组件(在层级中所有组件之上需要这个state的单个组件) + * 要么是共同拥有者,要么是其他在层级里更高级的组件应该拥有这个state + * 如果你不能找到一个组件,它拥有这个state有意义,创建一个新的组件简单的为了持有此state,并把它在层级里添加比共同拥有者组件更高的层级上. + +让我们过一遍这个用于我们应用的策略: + + * `ProductTable` 需要基于 state 过滤产品列表,`SearchBar` 需要显示搜索文本和选择状态. + * 共同拥有者组件是`FilterableProductTable` . + * 对于过滤文本和选择值存在于 `FilterableProductTable` 观念上是有意义的. + +酷,我们已经决定了我们的state存在于 `FilterableProductTable` .首先,添加一个 `getInitialState()` 方法到 `FilterableProductTable` ,返回 `{filterText: '', inStockOnly: false}` 来反映你的应用的初始状态. 然后,传递`filterText` 和 `inStockOnly` 给 `ProductTable` 和`SearchBar` 作为prop.最后,使用这些prop来过滤 `ProductTable` 中的行和设置`SearchBar`的表单项的值. + +你可以开始看看你的应用将有怎样的行为: 设置 `filterText` 为 `"ball"` 并刷新你的app.你将看到数据表被正确更新了. + +## 第五步:添加反向数据流 + + + +到目前为止,我们已经构建了一个应用, 它以props 和 state 沿着层级向下流动的功能正确渲染。现在是时候支持数据的另一种流动了:在层级深处的表单组件需要更新 `FilterableProductTable` 里的state. + +React 让数据显式流动,使理解你的应用如何工作变得简单,但是相对于传统的双向数据绑定,确实需要打多一些的字。 React 提供了一个叫做 `ReactLink` 的插件来使这种模式和双向数据绑定一样方便,但是考虑到这篇文章的目的,我们将会保持所有东西都直截了当。 + +如果你尝试在当前版本的示例中输入或者选中复选框,你会发现 React 忽略了你的输入。这是有意的,因为已经设置了 `input` 的 `value` prop 总是与 `FilterableProductTable` 传递过来的 `state` 一致。 + +让我们思考下我们希望发生什么。我们想确保每当用户改变了表单,我们就更新 state 来反映用户的输入。由于组件应该只更新自己拥有的 state , `FilterableProductTable` 将会传递一个回调函数给 `SearchBar` ,此函数每当 state 应被改变时就会击发。我们可以使用 input 的 `onChange` 事件来接受它的通知。 `FilterableProductTable` 传递的回调函数将会调用 `setState()` ,然后应用将会被更新。 + +虽然这听起来复杂,但是实际上只是数行代码。并且数据在应用中从始至终如何流动是非常明确的。 + +## 好了,就是这样 + +希望,这给了你一个怎样思考用React构建组件和应用的概念。虽然可能比你通常要输入更多的代码,记住,读代码的时间远比写代码的时间多,并且阅读这种模块化的,显式的代码是极端容易的。当你开始构建大型组件库时,你会非常感激这种清晰性和模块化,并且随着代码的重用,你的代码行数将会开始缩减. :)。 diff --git a/docs/tutorial.zh-CN.md b/docs/tutorial.zh-CN.md new file mode 100644 index 000000000..80fc0e540 --- /dev/null +++ b/docs/tutorial.zh-CN.md @@ -0,0 +1,712 @@ +--- +id: tutorial-zh-CN +title: 教程 +prev: getting-started-zh-CN.html +next: thinking-in-react-zh-CN.html +--- + +我们将建立一个你可以放进博客的简单却真实的评论框,一个 Disqus、LiveFyre 或 Facebook comments 提供的实时评论的基础版本。 + +我们将提供: + +* 一个所有评论的视图 +* 一个用于提交评论的表单 +* 为你提供制定后台的挂钩(Hooks) + +同时也会有一些简洁的功能: + +* **优化的评论:** 评论在它们保存到服务器之前就显示在列表里,所以感觉很快。 +* **实时更新:** 其他用户的评论被实时浮现到评论中。 +* **Markdown格式化:** 用户可以用Markdown格式化它们的文字。 + +### 想要跳过所有内容,只查看源代码? + +[全在 GitHub .](https://github.com/reactjs/react-tutorial) + +### 运行服务器 + +为了开始本教程,我们将要需要一个运行着的服务器。这将是我们纯粹用来获取和保存数据的伺服终端。为了让这尽可能的容易,我们已经用许多不同的语言编写了简单的服务器,它正好完成我们需要的事。 **你可以[查看源代码](https://github.com/reactjs/react-tutorial/) 或者 [下载 zip 文件](https://github.com/reactjs/react-tutorial/archive/master.zip) 包括了所有你开始学习需要的东西** + +为了简单起见,我们将要运行的服务器使用 `JSON` 文件作为数据库。你不会在生产环境运行这个,但是它让我们更容易模拟使用一个API时你可能会做的事。一旦你启动服务器,它将会支持我们的API终端,同时也将伺服我们需要的静态页面。 + +### 开始 + +对于此教程,我们将使它尽可能的容易。被包括在上面讨论的服务器包里的是一个我们将在其中工作的 HTML 文件。在你最喜欢的编辑器里打开 `public/index.html`。它应该看起来像这样 (可能有一些小的不同,稍后我们将添加一个额外的 ` + + + +
+ + + + +