React官网的RECENT POSTS阅读

⭐️写在开头

  • 阅读React官网的 RECENT POSTS的我的翻译/摘要(部分)。javascript

  • 英文片断为官网原文片断。html

  • 原文地址java

⭐️为何要使用React

目前已经有不少的JavaScript MVC frameworks出世,可是为何Facebook须要建立React,而且又是什么缘由致使咱们想要去用它?node

  • 不是一个MVC框架。是一个可用来构建组件化用户界面的库,同时力挺用于构建那些交互数据随时间改变的可复用的UI组件。python

  • 不是模板。传统的页面渲染(JavaScript渲染),是使用一些模板工具或者直接使用html标签进行:填充+拼接+渲染。这些构建UI的模板总体抽象了你想要的。react

Traditionally, web application UIs are built using templates or HTML directives. These templates dictate the full set of abstractions that you are allowed to use to build your UI.git

  • React以不一样的方式构建用户界面:分隔整个UI为一块一块小的UI组件UI Components。这就意味着咱们使用一门真实、充满特点的编程语言来渲染视图,其优于模板渲染有如下几个缘由:github

    • javaScript是一门灵活、强大的编程语言,其拥有构建抽象对象的能力。这一点在大型应用中很是重要。web

    • 经过将标记(标签)与相应的视图逻辑统一块儿来,React可以更加容易的进行扩展和维护视图。chrome

    • 经过JavaScript code的形式来代替标记(标签)和内容,这个过程没有字符拼接的过程而且减小了XSS漏洞。

同时建立了JSX,它是JavaScript的语法扩展。若是好比原生的JavaScript,你更喜欢HTML的可读性,就使用它吧!


不能再简单的响应式数据更新

当你的应用数据随着时间变化时,React表现是十分耀眼!

在传统的JavaScript应用中,你须要关注哪些数据变化了而且命令式的改变DOM的状态,以便保持视图和数据的一致。甚至经过指令和数据来提供了一种声明式界面的AngularJS,也是经过绑定须要的函数来手动更新DOM节点。

React采用不一样的方法:

  • 当组件初始化时调用render方法,而且生成一个轻量级的视图表达式。这个表达式将会返回一个标签字符串,而且插入页面文档中去。

  • 当数据变化的时候,render方法将被会再次调用。为了尽量的提升更新效率,咱们把先旧数据和新数据传入render方法进行对比,生成一个最小的变化来操做DOM。(render方法返回的值不是字符串也不是一个DOM元素,而是一个轻量级的DOM表达式)。


HTML仅仅只一个开始

因为React有着本身的轻量级的文本表达式,咱们能够作一些更酷的事情:

  • FaceBook使用React代替html绘制canvas动态图。

  • 结合React和Backbone.Rounter能够完美的构建单页应用(Instagram)。

  • 咱们在React内部原理处理,使得React App既能在web上运行,也能经过Objective-C bridge驱动原生IOS视图。

  • You can run React on the server for SEO, performance, code sharing and overall flexibility。

  • 事件行为在浏览器中保持一次,而且符合标准。默认使用事件代理。

⭐️React v0.3.3

咱们将在React v0.4中新增了许多中西,可是与此同时咱们发布了React v0.3.3。这个版本解决了人们在使用中遇到的问题,而且使咱们的工具更加容易使用。


React

容许反复使用同一个DOMNode渲染不一样的组件。

React.renderComponent(<div/>, domNode)

React.renderComponent(<span/>, domNode)

⭐️New in React v0.4: Prop Validation and Default Values

咱们收到关于React问题中,有大部分是关于props的,特别是人们但愿对props进行验证或者使其有个合理的默认值。


Validation

在使用props以前,咱们常常对props的某些参数进行某些特殊的处理,例如:须要肯定这些属性是不是特定的类型、需求限定某些值、某些参数的成分是必须的。这些验证咱们均可以在render里面处理,可是这回使render显得臃肿!

如今,React v.04带来的内建的验证模块,你能够写你本身的限定

React.createClass({
  propTypes: {
    // An optional string prop named "description".
    description: React.PropTypes.string,
    // A required enum prop named "category".
    category: React.PropTypes.oneOf(['News','Photos']).isRequired,
    // A prop named "dialog" that requires an instance of Dialog.
    dialog: React.PropTypes.instanceOf(Dialog).isRequired
  },
  ...
});

Default Values

在以往的例子里面,咱们常常看到如下代码:

React.createClass({
  render: function() {
    var value = this.props.value || 'default value';
    return <div>{value}</div>;
  }
});

若是对几个穿插在几个不一样组件的props进行以上操做,这将会产生大量的冗余代码。在React v0.04中,你能够以申明的方式提供默认值。

React.createClass({
  getDefaultProps: function() {
    return {
      value: 'default value'
    };
  }
  ...
});

在render以前,咱们使用这些函数进行处理(咱们也会在render以前支持全部的验证函数),以保证你在使用的时候拿到的数据是你所须要的。

Both of these features are entirely optional. We've found them to be increasingly valuable at Facebook as our applications grow and evolve, and we hope others find them useful as well.

⭐️React v0.4.1

React v0.4.1版本只是进行了小小的改动。主要是进行修复。部分代码在底层修改了,可是这不会影响你调用咱们的公共Api。


React

  • setState的callback参数,会在组件域调用。

  • click事件已经在移动Safari上支持。

  • 阻止已经在Object.prototype上存在的事件错误处理。

  • 不用设置先前就已经定义了的DOM属性为undefined。

  • 优化对iframe属性的支持。

  • 增长checksums属性来检测和校验服务端渲染和客户端实际渲染内容的是否一致。


JSXTransformer

改良环境检测机制,使其能运行在非浏览器环境。

Improved environment detection so it can be run in a non-browser environment.

⭐️Use React and JSX in Python Applications

今天咱们很高兴的宣布PyReact的初始版本的发布。它使得在你的pyhton应用中可以很好的使用ReactJSXPyReact设计的宗旨是提供一个转化JSXJavaScript的API。


Usage:show me code

from react import jsx
# For multiple paths, use the JSXTransformer class.
transformer = jsx.JSXTransformer()
for jsx_path, js_path in my_paths:
    transformer.transform(jsx_path, js_path)
# For a single file, you can use a shortcut method.
jsx.transform('path/to/input/file.jsx', 'path/to/output/file.js')

Django:support the pip

#install
$ pip install PyReact
#use
PIPELINE_COMPILERS = ( 'react.utils.pipeline.JSXCompiler',)

React Page

Jordan Walke 实现了一个完整的react项目react-page。其支持客户端和服务端的渲染、使用模板系统进行转化和打包、实时重载。

为何使用服务端渲染?

  • 提升页面初始化速度

    • 在下载JavaScript前,一些标签元素将会被展现给用户。

    • 在服务端标签元素的构建远远快于客户端。

  • 更快的开发和构建原型

  • 不用等待任何监听脚本或打包器。

  • 更容易的部署

  • SEO

服务端渲染是如何进行的?

  • 在服务端构建、发送标签给客户端,这样用户能够很快的看到内容。

  • 而后对应的JavaScript将会被打包送往客户端。

  • 浏览器运行对应JavaScript,这样全部的事件句柄、交互、数据更新等将会无缝隙的对服务端生成的标记进行绑定。

  • 肉眼看来这一切好像都是发生在客户端,只是更快。

⭐️ React v0.5


Changelog

  • 优化内存使用:经过使用 GC PAUSES(GC:Garbage Collection,垃圾收集,垃圾回收)机制,减小核心内存分配。

  • 提高性能:为了提供代码运行速度,咱们从V8和Nitro中剔除了一些slow path code

在网络设备里面区分不一样的路径是一个很天然的选择,由于网络设备的首要任务是转发网络包,不一样的网络包,在设备里面的处理路径不一样。fast path就是那些能够依据已有状态转发的路径,在这些路径上,网关,二层地址等都已经准备好了,不须要缓存数据包,而是能够直接转发。slow path是那些须要额外信息的包,好比查找路由,解析MAC地址等。

first path是设备收到流上第一个包所走过的路径,好比tcp里面的syn包,有些实现把三次握手都放到first path里面处理,而有些只需处理syn包,其余包就进入fast path的处理路径。

在NP或者ASIC里面也须要区分slow pathfast pathfast path上的包都放在SRAM里面,而slow path的包放在DRAM里面。不过这也非绝对。决定处理路径的是对于速度的考虑。处理器的速度,内存的速度等。访问内存的速度由速度和带宽两个因素决定。所以,把SRAM放到fast path上,也是很天然的选择。

fast path: Frontend -> simple code generator -> assembler
slow path: Frontend -> IR optimizer (sometimes more than one level of IR) -> code-generator -> assembler

  • 标准化支持:DOM属性的处理。在处理以前不只有多余的检查和开销,并且仍是混淆使用者。如今咱们会一直控制你的属性值为string直到渲染。

  • 支持Selection事件。

  • 支持混合事件(池化哟)。

  • 支持一些额外DOM属性:charSet, content, form, httpEquiv, rowSpan, autoCapitalize

  • 支持额外的SVG属性:rxry

  • 同时支持getInitialStategetDefaultProps

  • 支持挂载到iframes

  • 表单组件的bugfix

  • 增长react.version

  • 增长react.isValidClass:用户检查某个值是不是有效的组件构造函数。

  • 删除React.autoBind。在React v0.4中弃用,如今正式删除。

  • 重命名:React.unmountAndReleaseReactRootNodeReact.unmountComponentAtNode

  • 开始着手于精细的性能分析。

  • 更好的支持服务端渲染。

  • 是React运行于一个严格的安全策略下成为可能。同时使使用React编写chrome插件成为可能。


JSX

  • 属性class改名问className

  • 增长警告提示(非生产环境)。

  • 改善Window兼容性。

⭐️ React v0.9 [RC]

Upgrade Notes

咱们JSX解释器处理空格上面进行了改变。简单来讲就是,在一行上面组件与组件以前的空格将会被保留,而换行(文本节点或者组件)会被忽略。

<div>
  Monkeys:
  {listOfMonkeys} {submitButton}
</div>
0.8-
React.DOM.div(null,
  " Monkeys: ",
  listOfMonkeys, submitButton
)
0.9+
React.DOM.div(null,
  "Monkeys:",
  listOfMonkeys, " ", submitButton
)

相信这个新特性会很是有空,能够有效减小匆忙之中带来的非期待的空格。

若是你但愿保留 后面紧跟换行文本节点 后面的空格,那么你能够在JSX里面使用这种写法:{"Monkeys: }

⭐️ The Road to 1.0 (2014-03-28)

咱们在去年春天发布了React,可是咱们却有意的没有发布版本React v1.0。其实咱们已经作好了生产准备,可是咱们计划在内部和外部根据开发者怎么使用React来发展API和行为特性。在过去的九个月咱们学到了不少,而且思考不少关于1.0对于React意味着什么。在过去的两周内,我在多个项目里面概述了咱们打算进入1.0+的世界。今天我书写一点点给咱们的用户,以便用户更好的了解咱们的计划。

咱们在1.0中主要的目的是阐明咱们的消息模式,而且聚焦在一个与咱们目的相关的API上面进行处理。为了完成这个目的,咱们清除一些已经遇到的不友好的模式,真正的帮助开发者写出更好的代码。


ES6

在咱们正式推出React以前,咱们就思考过如何在React里面利用ES6,即类,以此来提升建立React组件的体验。咱们以为使用 React.createClass(…) 不是一个最好的选择。即便在使用方面优劣性没有正确的答案,可是咱们在向ES6方面靠拢。咱们但愿确保这个过程尽量的简单。例如:

class MyComponent extends React.Component {
  render() {
    ...
  }
}

其余一些ES6的特性咱们在React核心使用了。确信后面会有更多的特性加入。

JSXES6方面的支持咱们已经在react-tools里面搭船上线。已经支持转化大部分的ES6代码转换为老浏览器支持的代码。


Context

尽管咱们没有在文档中说起过context,可是它以某种形式在React确切存在的。

While we haven't documented context, it exists in some form in React already. It exists as a way to pass values through a tree without having to use props at every single point. We've seen this need crop up time and time again, so we want to make this as easy as possible. Its use has performance tradeoffs, and there are known weaknesses in our implementation, so we want to make sure this is a solid feature.

⭐️ React v0.11


getDefaultProps

从React0.11开始,getDefaultProps()只会在 React.createClass() 调用的时候调用一次,替代原来每次组件渲染时调用。这就意味着 getDefaultProps() 不会改变他的返回值,同时任何对象将会在全部实例中共享。这个改变提示了性能,而且使得未来可以更早的在渲染中作 PropTypes check ,这将使咱们可以给出更好的错误提示。


Rendering to null

自从React发布以来,开发者基本都遇到过 render nothing 的状况。一般是返回一个空<div/>或者<span/>。有些更聪明的人返回<noscript/>来避免不要的DOM nodes。咱们对此提供了一个解决办法:return null 。这样可以进一步帮忙开发者写出有意义的代码。在实现上,咱们使用了<noscript>标签进行处理,尽管咱们目的是不返回任何东西。由于noscript并不会影响你的布局,因此你能够放心使用。

// Before
render: function() {
  if (!this.state.visible) {
    return <span/>;
  }
  // ...
}
// After
render: function() {
  if (!this.state.visible) {
    return null;
  }
  // ...
}

JSX Namespacing

JSX里面支持namespaceing呼喊咱们已经听到了很长一段时间。考虑到JSX是JavaScript实现的,因此咱们不肯意使用XML namespaceing。相反,咱们使用选择JavaScript标准来实现: object property access。替代为每一个组件分配一个对象,你能够直接这样使用 <Namespace.Component />

// Before
var UI = require('UI');
var UILayout = UI.Layout;
var UIButton = UI.Button;
var UILabel = UI.Label;
render: function() {
  return <UILayout><UIButton /><UILabel>text</UILabel></UILayout>;
}
// After
var UI = require('UI');
render: function() {
  return <UI.Layout><UI.Button /><UI.Label>text</UI.Label></UI.Layout>;
}

Improved keyboard event normalization

根据DOM3,React键盘事件包含了一个标准化的 e.key ,这样容许你在代码中编写一个简单的key,而且可以在全部浏览器运行。

handleKeyDown: function(e) {
  if (e.key === 'Enter') {
    // Handle enter key
  } else if (e.key === ' ') {
    // Handle spacebar
  } else if (e.key === 'ArrowLeft') {
    // Handle left arrow
  }
}

React键盘事件和鼠标事件也包含了标准化的 e.getModifierState()

⭐️ Flux: Actions and the Dispatcher

Flux是Facebook构建JavaScript应用的时候使用的基于单项数据流的应用框架。咱们使用Flux的构建大型应用都是有小的组件组成,Flux来控制咱们提供的小组件(们)。咱们找到了一个很是棒的代码组织结构,咱们十分激动的分享到开源社区。

好比一个完整的框架,Flux更像一种模式,让你不用增长太多新代码就可以使用Flux。直到最近的,咱们尚未发布Flux模块之一: dispatcher。可是随着新的Flux code项目和Flux website发布,咱们提供咱们在生产项目中使用的dispatcher


Where the Dispatcher Fits in the Flux Data Flow

dispatcher是一个单例。做为数据控制中心控制Flux应用的数据流。简单的来讲,他就是提供注册回调函数,而后使用必定的命令调用这些回调函数。每一个store都经过dispatcher注册了回调。当dispatcher中有新数据来,它使用这些回调通知相应的store。而后相关程序经过dispatch()启动回调函数。


Actions and ActionCreators

不管是用户进行界面操做仍是接口返回的新数据进入系统的时候,这些数据将会被打包送入一个 action(由内容和action type组成的对象)。对此,咱们经常建立名为ActionCreateors的辅助库,用来建立action object和传递actiondispatcher

不一样的actioins由一个type属性定义。当全部的stores收到action的时候,它们就使用这个属性来决定怎么响应它。在Flux应用中,storesviews彼此自我控制,它们不会被外部影响。操做流经过stores定义注册的回调进入store, not through setter methods。

使stores自我更新可以避免不少一些MVC应用的复杂状况,例如:各个models之间的联合更新会致使状态的不稳定而且会致使测试很是困难。objectsFlux应用中高度分离,而且严格准守得墨忒耳定律。这样会致使软件更加可维护、适配、测试以及对新工程师来谁更加容易理解。


Why We Need a Dispatcher

随着应用的壮大,不一样stores之间的依赖必然存在。例如:Store A 必须 Store A 先更新,而后 Store A才知道如何去更新本身。这个时候咱们就须要dispatcher可以调用 Store B的回调,以后再操做Store A。为了申明这种依赖,Store A 须要告诉dispatcher,我须要等待Store B完成后才能执行这个actiondispatcher经过 waitFor()提供这样的功能。

dispatch()方法经过回调函数提供了一个简单的、同步迭代功能:依次调用。当waitFor()在某一个回调中触发,随后中止执行这个回调函数,而且 waitFor()将提供咱们一个有关依赖的新的迭代周期。等这些依赖执行完之后,回调函数再继续执行。

更者,waitFor()方法但是在同一个store中不不一样的actions间调用。

Problems arise, however, if we have circular dependencies. That is, if Store A needs to wait for Store B, and Store B needs to wait for Store A, we could wind up in an endless loop. The dispatcher now available in the Flux repo protects against this by throwing an informative error to alert the developer that this problem has occurred. The developer can then create a third store and resolve the circular dependency.

⭐️Introducing React Elements

If you currently use JSX everywhere, you don't really have to do anything to get these benefits! The updated transformer will do it for you.
If you can't or don't want to use JSX, then please insert some hints for us. Add a React.createFactory call around your imported class when you require it。


New Terminolog

咱们为了使新用户更简单的了解DOM(和React的不一样之处)。咱们使用术语ReactElement代替<>,一样ReactNode代替renderable


Creating a ReactElement

咱们提供一个API来建立ReactElement

var reactElement = React.createElement(type,props,children);

type参数可使HTML tag或者class。它指示着什么样的HTML tag或者class将被渲染和包含哪些props数据。你也能够只提供一个type参数建立一个工程函数。

var div = React.createFactory('div');
var reactDivElement = div(props,children);

React Element的签名就像这样

{
  type : string | class,
  props : { children, className, etc. },
  key : string | boolean | number | null,
  ref : string | null
}

Upgrading to 0.12

React With JSX

若是你使用ReactJSX转化器,这个升级将会很是简单。

// If you use node/browserify modules make sure
// that you require React into scope.
var React = require('react');

React的JSX将会为你建立ReactElement

var MyComponent = React.createClass(...);
var MyOtherComponent = React.createClass({
  render: function() {
    return <MyComponent prop="value" />;
  }
});

React Without JSX

在不使用JSX状况下须要调用一个组件做为函数,在调用前你须要明确的建立一个工程函数。

var MyComponentClass = React.createClass(...);
var MyComponent = React.createFactory(MyComponentClass); // New step
var MyOtherComponent = React.createClass({
  render: function() {
    return MyComponent({ prop: 'value' });
  }
});

React为常见的HTML elements内置了工厂函数。

var MyDOMComponent = React.createClass({
  render: function() {
    return React.DOM.div({ className: 'foo' }); // still ok
  }
});

The Next Step: ES6 Classes

在v0.12版本后,咱们的工做将转向ES6 classes。咱们会保持向后兼容(React.createclass)。若是你已经在使用ES6转译器,你能够按照下面申明你的组件。

export class MyComponent {
    render(){
        ...
    }
};

⭐️Deprecating JSTransform and react-tools

随着JavaScript的发展,JSTransform有点"跟不上时代",Babel的出现能够彻底将其替代。v0.14之后将不会再维护JSTransformreact-toolsreact-tools has always been a very thin wrapper around JSTransform.),ReactReact Native目前都使用三方的Babel的JSX编译器处理.


Other Deprecations

esprima-fb

ECMAScript解析器

JSXTransformer

JSXTransformer is another tool we built specifically for consuming JSX in the browser. It was always intended as a quick way to prototype code before setting up a build process. It would look for <script> tags with type="text/jsx" and then transform and run. This ran the same code that react-tools ran on the server.

⭐️ReactDOM.render and the Top Level React API

React的世界里面全部都是组件,可是你涉及的代码、工程并非都是由React来构建的。因此,须要你编写管道代码进行二者的连接。处理这些事情的主要API为:

ReactDOM.render(reactElment,domContainerNode)

这须要你提供一个额外的DOM容器。

当把React插入在单页应用中时候,须要你手动的控制生命周期。React不会自动释放元素,须要手动控制:

ReactDOM.unmountComponentAtNode(domComtainerNode)

It is not unique to the DOM. If you want to insert a React Native view in the middle of an existing iOS app you will hit similar issues.

Object Oriented Updates

若是你调用ReactDOM.render屡次,那么对应组件上次的props将会被最新的彻底替代。

ReactDOM.render(<App locale="en-US" userID={1} />, container);
// props.userID == 1
// props.locale == "en-US"
ReactDOM.render(<App userID={2} />, container);
// props.userID == 2
// props.locale == undefined ??!?

在面向对象编程中,全部的状态依赖实例存在,经过控制状态的改变控制应用变化。若是你在一个使用面向对象API的app里面使用React,你也许会惊讶或者迷茫当你设置一个属性的时候会致使其余属性的消失。

对此咱们提供了一个辅助函数setProps来容许你一次只更新所指望的属性。

Unfortunately this API lived on a component instance, required React to keep this state internally and wasn't very natural anyway. Therefore, we're deprecating it and suggest that you build it into your own wrapper instead.

class ReactComponentRenderer {
  constructor(klass, container) {
    this.klass = klass;
    this.container = container;
    this.props = {};
    this.component = null;
  }
  replaceProps(props, callback) {
    this.props = {};
    this.setProps(props, callback);
  }
  setProps(partialProps, callback) {
    if (this.klass == null) {
      console.warn(
        'setProps(...): Can only update a mounted or ' +
        'mounting component. This usually means you called setProps() on ' +
        'an unmounted component. This is a no-op.'
      );
      return;
    }
    Object.assign(this.props, partialProps);
    var element = React.createElement(this.klass, this.props);
    this.component = ReactDOM.render(element, this.container, callback);
  }
  unmount() {
    ReactDOM.unmountComponentAtNode(this.container);
    this.klass = null;
  }
}

Object-oriented APIs don't look like that though. They use setters and methods. I think we can do better. If you know more about the component API that you're rendering, you can create a more natural object-oriented API around your React component.

class ReactVideoPlayer {
  constructor(url, container) {
    this._container = container;
    this._url = url;
    this._isPlaying = false;
    this._render();
  }
  _render() {
    ReactDOM.render(
      <VideoPlayer url={this._url} playing={this._isPlaying} />,
      this._container
    );
  }
  get url() {
    return this._url;
  }
  set url(value) {
    this._url = value;
    this._render();
  }
  play() {
    this._isPlaying = true;
    this._render();
  }
  pause() {
    this._isPlaying = false;
    this._render();
  }
  destroy() {
    ReactDOM.unmountComponentAtNode(this._container);
  }
}

⭐️React Components, Elements, and Instances

ComponentsElementsComponent instrances三者的不一样也许迷惑着许多初学者。为何三个不一样的事物合做可以在屏幕上绘图。

Managing the Instances

若是你是初学者,你也许开始是和Component classesComponent classes Instances打交道。栗如,建立class来申明Button组件。当应用运行时,你可能有Button组件的多个实例,每一个实例有着本身的属性和本地状态。这是传统的面向对象的UI编程。

在传统的UI模块中,由你来控制建立和销毁组件实例。栗:若是一个Form组件要渲染一个Button组件。它须要一个Button的实例而且手动保持和任何信息的交流。

class Form extends TraditionalObjectOrientedView {
  render() {
    // Read some data passed to the view
    const { isSubmitted, buttonText } = this.attrs;
    if (!isSubmitted && !this.button) {
      // Form is not yet submitted. Create the button!
      this.button = new Button({
        children: buttonText,
        color: 'blue'
      });
      this.el.appendChild(this.button.el);
    }
    if (this.button) {
      // The button is visible. Update its text!
      this.button.attrs.children = buttonText;
      this.button.render();
    }
    if (isSubmitted && this.button) {
      // Form was submitted. Destroy the button!
      this.el.removeChild(this.button.el);
      this.button.destroy();
    }
    if (isSubmitted && !this.message) {
      // Form was submitted. Show the success message!
      this.message = new Message({ text: 'Success!' });
      this.el.appendChild(this.message.el);
    }
  }
}

上面的伪复合UI代码(或者增长更多)都是按照面向对象的方式使用库,就像Backbone同样。每一个组件实例都保持DOM nodeChild Component关联而且在合适的时间建立/销毁(DOM nodeChild Component)。随着代码量的增长,组件可能的状态数会按平方级增加,而且父级能够直接访问子组件的实例,未来想要解偶就会变的很是困难。

比起上述,React有什么不一样?

Elements Describe the Tree

为解决上述问题,React里面出现了ElementsAn element is a plain object describing a component instance or DOM node and its desired properties.它包含了一些惟一的信息:组件类型(Button)、属性(color)和拥有的Child Elements

PlainObject:JSON形式定义的普通对象或者new Object()建立的简单对象。

一个Element不是一个实际的实例。相反,他是一种告诉React什么须要渲染在屏幕上的方式。你不能调用任何在Elements上面的方法,它仅仅是一个拥有两个字段属性的不可变对象(type : ( string | ReactClass )props : Object)。

DOM Elements

Elementtype是一个字符串时,它表明着一个拥有props做为属性的DOM node(这些就是React将会渲染的)。栗子:

{
  type: 'button',
  props: {
    className: 'button button-blue',
    children: {
      type: 'b',
      props: {
        children: 'OK!'
      }
    }
  }
}
⇩
<button class='button button-blue'>
  <b>
    OK!
  </b>
</button>

对于Elements嵌套的问题,按照惯例,咱们但愿建立一个Elements树,而后指定一个或者多个Child Elements做为其容器/父元素的children props

最重要的一点仍是Child ElementsParent Elements仅仅只一中描述方式并非真实实例。当你建立它们的时候并不涉及在屏幕上面呈现的东西。建立和丢弃他们都是可有可无的。

React elements are easy to traverse, don’t need to be parsed, and of course they are much lighter than the actual DOM elements—they’re just objects!

Component Elements

而后Elementstype参数可使一个React Component对应的函数或者类。

{
    type : Button,
    props : {
        color : "blue",
        children : "OK!",
    }
}

这是React的核心思想。

An element describing a component is also an element, just like an element describing the DOM node. They can be nested and mixed with each other.

这个特性可让你建立一个DangerButton,它是一个拥有特定color属性值的Button组件。而且不用小心Button是否渲染为DOM <button><div>或者其余的。

const DangerButton = ({ children }) => ({
  type: Button,
  props: {
    color: 'red',
    children: children
  }
});

你能够混合搭配DOM/Component Elements在一个简单的Element Tree里面。

const DeleteAccount = () => ({
  type: 'div',
  props: {
    children: [{
      type: 'p',
      props: {
        children: 'Are you sure?'
      }
    }, {
      type: DangerButton,
      props: {
        children: 'Yep'
      }
    }, {
      type: Button,
      props: {
        color: 'blue',
        children: 'Cancel'
      }
   }]
});

或者你使用JSX

const DeleteAccount = () => (
  <div>
    <p>Are you sure?</p>
    <DangerButton>Yep</DangerButton>
    <Button color='blue'>Cancel</Button>
  </div>
);

这种混合和匹配有助于下降组件之间的耦合度,所以它们彻底能够经过一下的结构同时表达is-a和has-a的关系

  • Button组件是一个具备特定属性的DOM元素button;

  • DangerButton组件是一个具备特定属性的Button组件;

  • DeleteAccount在一个div元素中包含一个Button组件和一个DangerButton组件。

Components Encapsulate Element Trees

React收到一个使用函数或者类做为type值得Element的时候,它知道询问对应的组件什么样的Element须要被渲染,并给予相应的props

当看到这个Element的时候

{
  type: Button,
  props: {
    color: 'blue',
    children: 'OK!'
  }
}

React将会询问Button Component什么须要渲染。Button Component将会返回

{
  type: 'button',
  props: {
    className: 'button button-blue',
    children: {
      type: 'b',
      props: {
        children: 'OK!'
      }
    }
  }
}

React将重复此过程,直到它知道页面上的每一个组件有用的底层DOM标签元素。

前面提到的Form实例使用React能够这样

const Form = ({ isSubmitted, buttonText }) => {
  if (isSubmitted) {
    // Form submitted! Return a message element.
    return {
      type: Message,
      props: {
        text: 'Success!'
      }
    };
  }
  // Form is still visible! Return a button element.
  return {
    type: Button,
    props: {
      children: buttonText,
      color: 'blue'
    }
  };
};

以上,对于React Component组件,props是输入,Element Tree是输出。

The returned element tree can contain both elements describing DOM nodes, and elements describing other components. This lets you compose independent parts of UI without relying on their internal DOM structure.

返回的元素树包括描述DOM node及描述其它Component。这可让咱们独立地编写UI部分,而无需依赖它们的内部DOM结构。

咱们使React建立、更新、销毁实例。

咱们使用Components返回的Elements描述实例,React负责管理实例。

Components Can Be Classes or Functions

// 1) As a function of props
const Button = ({ children, color }) => ({
  type: 'button',
  props: {
    className: 'button button-' + color,
    children: {
      type: 'b',
      props: {
        children: children
      }
    }
  }
});
// 2) Using the React.createClass() factory
const Button = React.createClass({
  render() {
    const { children, color } = this.props;
    return {
      type: 'button',
      props: {
        className: 'button button-' + color,
        children: {
          type: 'b',
          props: {
            children: children
          }
        }
      }
    };
  }
});
// 3) As an ES6 class descending from React.Component
class Button extends React.Component {
  render() {
    const { children, color } = this.props;
    return {
      type: 'button',
      props: {
        className: 'button button-' + color,
        children: {
          type: 'b',
          props: {
            children: children
          }
        }
      }
    };
  }
}

When a component is defined as a class, it is a little bit more powerful than a functional component. It can store some local state and perform custom logic when the corresponding DOM node is created or destroyed.

A functional component is less powerful but is simpler, and acts like a class component with just a single render() method. Unless you need features available only in a class, we encourage you to use functional components instead.

Top-Down Reconciliation

ReactDOM.render({
  type: Form,
  props: {
    isSubmitted: false,
    buttonText: 'OK!'
  }
}, document.getElementById('root'));

你当运行上述代码的时候,React会询问Form组件返回的Element Tree,给予对应props

// React: You told me this...
{
  type: Form,
  props: {
    isSubmitted: false,
    buttonText: 'OK!'
  }
}
// React: ...And Form told me this...
{
  type: Button,
  props: {
    children: 'OK!',
    color: 'blue'
  }
}
// React: ...and Button told me this! I guess I'm done.
{
  type: 'button',
  props: {
    className: 'button button-blue',
    children: {
      type: 'b',
      props: {
        children: 'OK!'
      }
    }
  }
}

This is a part of the process that React calls reconciliation which starts when you call ReactDOM.render() or setState(). By the end of the reconciliation, React knows the result DOM tree, and a renderer like react-dom or react-native applies the minimal set of changes necessary to update the DOM nodes (or the platform-specific views in case of React Native).

You might have noticed that this blog entry talks a lot about components and elements, and not so much about the instances. The truth is, instances have much less importance in React than in most object-oriented UI frameworks.

Summary

Element只是是PlainObject,用来描述呈如今屏幕上的DOM node或其它ComponentElements的props中能够包含其它Elements。建立ReactReact Element是廉价的,一旦建立了React Element,就不会再发生变化。

一个组件的申明有几个不一样的方式:classfunctionReact.creatClass。不管哪一种方式,老是props为输入,Element Tree为输出。

An instance is what you refer to as this in the component class you write. It is useful for storing local state and reacting to the lifecycle events.(实例就是对组件类中this的引用。)

最后,建立React Elements使用React.createElement()JSX或者Element Factory helper。别在实际代码中编写PlainObect形式的Elements(只须要知道在底层他们是PlainObject就好了)。

⭐️(A => B) !=> (B => A)

文档里面对于componentWillReceiveProps的陈述为:componentWillReceiveProps在对应props被改变的时候调用,并做为rerender的结果。这致使部分用户认为:componentWillReceiveProps被调用了对应props必定会变化。逻辑上这个结论是不正确的。

formal logic/mathematics:A包含着B,不表明B包含着A。有不少缘由致使componentWillReceiveProps被调用,即便对应的props没有改变。

你若是不相信,能够试试使用准确的props三次调用ReactDOM.render(),而且监控componentWillReceiveProps的调用。

class Component extends React.Component {
  componentWillReceiveProps(nextProps) {
    console.log('componentWillReceiveProps', nextProps.data.bar);
  }
  render() {
    return <div>Bar {this.props.data.bar}!</div>;
  }
}
var container = document.getElementById('container');
var mydata = {bar: 'drinks'};
ReactDOM.render(<Component data={mydata} />, container);
ReactDOM.render(<Component data={mydata} />, container);
ReactDOM.render(<Component data={mydata} />, container);

以上代码componentWillReceiveProps会被调用两次。

为了理解为何会这样,咱们须要想一想会发生什么。在初始渲染和两次后续更新之间数据可能已经被改变了,若是代码像下面这样执行:

var myData = {
    bar: 'drinks'
};
ReactDOM.render(<Component data={myData} />, container);
myData.bar = 'food';
ReactDOM.render(<Component data={myData} />, container);
myData.bar = 'noise';
ReactDOM.render(<Component data={myData} />, container);

数据没有改变,但React并无办法知道。所以,React须要调用componentWillReceiveProps方法,由于组件须要新props来通知(即便新的props和旧props彻底相同)。

你可能会认为,React可使用很巧妙的检测机制来检测是否相等,但这种想法也有一些问题

  • 旧的myData和新的myData其实是相同的物理对象(仅对象内部的值被改变)。因为采用的是triple-equals-equal,检查是否相同的时候并不会告诉咱们值是否被改变。唯一可能的解决方法就是建立数据的一个深拷贝副本,接着作深比较,但这对比较大的数据结构而言过于昂贵(特别是循环)

  • myData对象可能包括对函数的引用,该函数经过闭包获取变量。React没有办法获取闭包内部的变量值,所以也没有办法复制和验证它们是否相等

  • myData可能包括父级渲染时从新实例化了的实例对象的引用,但概念上是相等的(具备相同的keyvalue)。深比较能够检测到这一点,除过这点又会出现新的问题,由于没有办法比较两个函数在语义上是否相同。

因为语言的限制,有时咱们不可能实现真正意义上相等的语义。在这种状况下,React会调用componentWillReceiveProps方法(即便props可能没有改变),使得组件有机会检测新的props,并采起相应的处理。

这样一来,实现componentWillReceiveProps方法时候要确保props不能被修改。若是你想在props被改变后执行一些操做(如网络请求),你的componentWillReceiveProps代码须要检查props是否真正的被改变了。

相关文章
相关标签/搜索