[react] React 基础
可以在服务端渲染view层
React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。
React 来决定如何最高效地更新 DOM。
常用的通知 React 数据变化的方法是调用 setState(data, callback)。
这个方法会合并(merge) data 到 this.state,并重新渲染组件。
渲染完成后,调用可选的 callback 回调。大部分情况下不需要提供 callback,因为 React 会负责把界面更新到最新状态。
state 应该包括那些可能被组件的事件处理器改变并触发用户界面更新的数据。
this.state 应该仅包括能表示用户界面状态所需的最少数据。因此,它不应该包括:
    
    计算所得数据: 不要担心根据 state 来预先计算数据 —— 把所有的计算都放到 render() 里更容易保证用户界面和数据的一致性。
    例如,在 state 里有一个数组(listItems),我们要把数组长度渲染成字符串, 直接在 render() 里使用 this.state.listItems.length + ' list items' 比把它放到 state 里好的多。
    
    React 组件: 在 render() 里使用当前 props 和 state 来创建它。
    基于 props 的重复数据: 尽可能使用 props 来作为惟一数据来源。
    把 props 保存到 state 的一个有效的场景是需要知道它以前值的时候,因为未来的 props 可能会变化。
做细粒度的性能控制。这种情况下,可以重写 shouldComponentUpdate() 方法返回 false 来让 React 跳过对子树的处理。
但是注意:
如果在数据变化时让 shouldComponentUpdate() 返回 false,React 就不能保证用户界面同步。
当使用它的时候一定确保清楚到底做了什么,并且只在遇到明显性能问题的时候才使用。
不要低估 JavaScript 的速度,DOM 操作通常才是慢的原因。
React 组件只能渲染单个根节点。如果要返回多个节点,它们必须被包含在同一个节点里。
props - "properties"的缩写。它通过 JSX 语法进行参数传递。
在组件里这些属性是不可直接改变的,也就是 this.props 是只读的。
不要轻易修改props
render() 方法依赖于 this.props 和 this.state ,框架会确保渲染出来的 UI 界面总是与输入( this.props 和 this.state )保持一致。
由于 JSX 就是 JavaScript,一些标识符像 class 和 for 不建议作为 XML 属性名。
作为替代,React DOM 使用 className 和 htmlFor 来做对应的属性。
 react: react核心库,包含创建组件的类和函数
react-dom:页面呈现库,包含react组件或元素在浏览器呈现的函数,主要是render函数
Properties对Component,从形式上,类似HTML元素的attributes
Properties在创建Component时指定
运行时State用来定制Component
State用来存储Component可能变化的内容
getInitialState 初始化
setState触发React重新渲染Component
Properties用在Component创建的时候,可以通过JSX(或纯Javascript)由外部传入,描述的是Component初始化时所需要的信息,
而State只能在Component的内部定义,描述的是Component内部影响其内容、样式、行为的动态内容集合,可以理解为私有变量。
Properties是由Component暴露给使用者,由使用者传递给Component;
而State则是由Component自己控制,State的变化(setState)会触发React的重绘机制,从而实现Component响应外部的操作等。
    将应用拆分为Component
    大部分Component是利用Properties做展示
    包装较少的Component来管理State,响应变化
    React通过State变化,刷新相关Component
React的事件名采用驼峰方式
这类组件默认不响应任何用户输入
    input 、textarea/ value
    input(type='checkbox' or ’radio‘) / checked
    option/ selected
要能响应用户输入,有两种方式:
    使用defaultValue替换value (这是这个Component变成了一个Uncontrolled Components)
    提供回调函数,并且“手动“设置input的value
    
#
JSX
#与 DOM 的差别
React 为了性能和跨浏览器的原因,实现了一个独立于浏览器的事件和 DOM 系统。
    所有 DOM 的 properties 和 attributes (包括事件处理器)应该都是驼峰命名的,以便和标准的 JavaScript 风格保持一致。除了data-* 和 aria-* 。
    
    style 属性接收一个带有驼峰命名风格的 JavaScript 对象,而不是一个 CSS 字符串。这与 DOM 中的 style 的 JavaScript 属性保持一致,更加有效,并且弥补了 XSS 安全漏洞。
    
    所有的事件对象和 W3C 规范保持一致,并且所有的事件(包括提交事件)冒泡都正确地遵循 W3C 规范。
    
    onChange 事件表现得和你想要的一样:当表单字段改变了,该事件就被触发,而不是等到失去焦点的时候。
    和现有的浏览器表现得不一致。
    
    表单输入属性,例如 value 和 checked,以及 textarea
#JSX 表达式总是会当作 ReactElement 执行。
一种优化 的模式是把 ReactElement 当作一个行内的对象字面量形式来绕过 React.createElement 里的校验代码。
#渲染 HTML 标签,JSX 里使用小写字母开头的标签名。
var myDivElement = <div className="foo" />; React.render(myDivElement, document.body);
#渲染 React 组件,创建一个大写字母开头的本地变量。
var MyComponent = React.createClass({/*...*/}); var myElement = <MyComponent someProperty={true} />; React.render(myElement, document.body);
#
var Nav; // 输入 (JSX): var app = <Nav color="blue" />; // 输出 (JS): var app = React.createElement(Nav, {color:"blue"}); var Nav, Profile; // 输入 (JSX): var app = <Nav color="blue"><Profile>click</Profile></Nav>; // 输出 (JS): var app = React.createElement( Nav, {color:"blue"}, React.createElement(Profile, null, "click") );
属性表达式
// 输入 (JSX): var person = <Person name={window.isLoggedIn ? window.name : ''} />; // 输出 (JS): var person = React.createElement( Person, {name: window.isLoggedIn ? window.name : ''} );
子节点表达式
// 输入 (JSX): var content = <Container>{window.isLoggedIn ? <Nav /> : <Login />}</Container>; // 输出 (JS): var content = React.createElement( Container, null, window.isLoggedIn ? React.createElement(Nav) : React.createElement(Login) );
注释
在一个标签的子节点内(非最外层)小心地用 {} 包围要注释的部分。
var content = ( <Nav> {/* 非最外层注释, 用 {} 包围 */} <Person /* 多 行 注释 */ name={window.isLoggedIn ? window.name : ''} // 行尾注释 /> </Nav> );
Boolean Attributes
// These two are equivalent in JSX for disabling a button <input type="button" disabled />; <input type="button" disabled={true} />; // And these two are equivalent in JSX for not disabling a button <input type="button" />; <input type="button" disabled={false} />;
延展属性(Spread Attributes)
//传入对象的属性会被复制到组件内 var props = {}; props.foo = x; props.bar = y; var component = <Component {...props} />;
#
//延展属性能被多次使用,也可以和其它属性一起用。但是顺序很重要,后面的会覆盖掉前面的。 var props = { foo: 'default' }; var component = <Component {...props} foo={'override'} />; console.log(component.props.foo); // 'override'
#使用实体符号
最好使用Unicode 字符 或 实体Unicode 编号
<div>{'First \u00b7 Second'}</div>
<div>{'First ' + String.fromCharCode(183) + ' Second'}</div>
可以在数组里混合使用字符串和 JSX 元素。
<div>{['First ', <span>·</span>, ' Second']}</div>
万不得已可以直接使用原始 HTML。
<div dangerouslySetInnerHTML={{__html: 'First · Second'}} />
#自定义属性
如果往原生 HTML 元素里传入 HTML 规范里不存在的属性,React 不会显示它们。如果需要使用自定义属性,要加 data- 前缀。
<div data-custom-attribute="foo" />
然而,自定义元素(那些标签名里面有连字符或者有 is="..." 属性)支持任意属性。
<x-my-component custom-attribute="foo" />
以 aria- 开头的 [网络无障碍] 属性可以正常使用。
<div aria-hidden={true} />
#
React.render疑似被ReactDOM.render替代
ReactComponent render(
  ReactElement element,
  DOMElement container,
  [function callback]
)
渲染一个 ReactElement 到 DOM 中,放在 container 指定的 DOM 元素下,返回一个到该组件的引用。
如果 ReactElement 之前就被渲染到了 container 中,该函数将会更新此 ReactElement,仅改变需要改变的 DOM 节点以展示最新的 React 组件。
如果提供了可选的回调函数,则该函数将会在组件渲染或者更新之后调用。
注意:
React.render() 替换传入的容器节点内容。(在将来,或许可能插入组件到已存在的 DOM 节点中,但不覆盖已有的子节点)。
React.createClass
ReactClass createClass(object specification)
创建一个组件类,并作出定义。组件实现了 render() 方法,该方法返回一个子级。该子级可能包含很深的子级结构。组件与标准原型类的不同之处在于,你不需要使用 new 来实例化。 组件是一种很方便的封装,可以(通过 new )为你创建后台实例。
React.createElement
ReactElement createElement(
  string/ReactClass type,
  [object props],
  [children ...]
)
创建并返回一个新的指定类型的 ReactElement。type 参数可以是一个 html 标签名字字符串(例如,“div”,“span”,等等),或者是 ReactClass (通过 React.createClass 创建的)。
React.createFactory
factoryFunction createFactory(
  string/ReactClass type
)
返回一个生成指定类型 ReactElements 的函数。比如 React.createElement,type 参数可以是一个 html 标签名字字符串(例如,“div”,“span”,等等),或者是 ReactClass。
React.Component
class Component
This is the base class for React Components when they're defined using ES6 classes.
React.DOM
React.DOM 运用 React.createElement 为 DOM 组件提供了方便的包装。该方式仅在未使用 JSX 的时候适用。例如,React.DOM.div(null, 'Hello World!')。
React.PropTypes 
包含了能与组件 propTypes 对象共用的类型,用于验证传入组件的 props。
#
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, // 所有可以被渲染的对象:数字, // 字符串,DOM 元素或包含这些类型的数组。 optionalNode: React.PropTypes.node, // React 元素 optionalElement: React.PropTypes.element, // 用 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( 'Invalid prop `' + propName + '` supplied to' + ' `' + componentName + '`. Validation failed.' ); } }, // You can also supply a custom validator to `arrayOf` and `objectOf`. // It should return an Error object if the validation fails. The validator // will be called for each key in the array or object. The first two // arguments of the validator are the array or object itself, and the // current item's key. customArrayProp: React.PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) { if (!/matchme/.test(propValue[key])) { return new Error( 'Invalid prop `' + propFullName + '` supplied to' + ' `' + componentName + '`. Validation failed.' ); } }) }, /* ... */ });
#title Properties 为必选
React.createClass({ propTypes: { title: React.PropTypes.isRequired }, render: function() { return <h1>{this.props.title}</h1>; } });
#title Properties 为string类型
React.createClass({ propTypes: { title: React.PropTypes.string }, render: function() { return <h1>{this.props.title}</h1>; } });
#title Properties 为string类型,同时必选
React.createClass({ propTypes: { title: React.PropTypes.string.isRequired }, render: function() { return <h1>{this.props.title}</h1>; } });
#Properties默认值 getDefaultProps
React.createClass({ getDefaultProps : function() { return { title : "I am the default value." }; }, propTypes: { title: function(props, propName, componentName){ if (!(propName in props)) { throw new Error("title must be set."); } var title = props[propName]; if(typeof title !== 'string'){ throw new Error("title must be a string."); } if(title.length == 0){ throw new Error("title must not be empty."); } } }, render: function() { return <h1>{this.props.title}</h1>; } });
this.props.children
取得当前组件的子元素
React.Children 
为处理 this.props.children 这个封闭的数据结构提供了有用的工具。
#React.Children.map
object React.Children.map(object children, function fn [, object context])
在每一个直接子级(包含在 children 参数中的)上调用 fn 函数,此函数中的 this 指向 上下文。如果 children 是一个内嵌的对象或者数组,它将被遍历:不会传入容器对象到 fn 中。如果 children 参数是 null 或者 undefined,那么返回 null 或者 undefined 而不是一个空对象。
#React.Children.forEach
React.Children.forEach(object children, function fn [, object context])
类似于 React.Children.map(),但是不返回对象。
#React.Children.count
number React.Children.count(object children)
返回 children 当中的组件总数,和传递给 map 或者 forEach 的回调函数的调用次数一致。
#React.Children.only
object React.Children.only(object children)
返回 children 中仅有的子级。否则抛出异常。
#React.Children.toArray
array React.Children.toArray(object children)
Return the children opaque data structure as a flat array with keys assigned to each child. 
Useful if you want to manipulate collections of children in your render methods,
especially if you want to reorder or slice this.props.children before passing it down.
React.findDOMNode疑似废除
React.findDOMNode(component)
获取该组件的DOM结点。
    注意:
    findDOMNode()仅在挂载的组件上有效(也就是说,组件已经被放进了DOM中)。
    如果尝试在一个未被挂载的组件上调用这个函数(例如在创建组件的render()函数中调用findDOMNode()),将会抛出异常。
为了获取一个到React组件的引用,可以使用this来得到当前的React组件,或者使用refs来指向一个拥有的组件。
displayName
string displayName
displayName 字符串用于输出调试信息。
setState
setState(object nextState[, function callback])
合并 nextState 和当前 state。这是在事件处理函数中和请求回调函数中触发 UI 更新的主要方法。另外,也支持可选的回调函数,该函数在 setState 执行完毕并且组件重新渲染完成之后调用。
注意:
绝对不要直接改变 this.state,因为在之后调用 setState() 可能会替换掉你做的更改。把 this.state 当做不可变的。
setState() 不会立刻改变 this.state,而是创建一个即将处理的 state 转变。在调用该方法之后获取 this.state 的值可能会得到现有的值,而不是最新设置的值。
不保证 setState() 调用的同步性,为了提升性能,可能会批量执行 state 转变和 DOM 渲染。
setState() 将总是触发一次重绘,除非在 shouldComponentUpdate() 中实现了条件渲染逻辑。如果使用可变的对象,但是又不能在 shouldComponentUpdate() 中实现这种逻辑,仅在新 state 和之前的 state 存在差异的时候调用 setState() 可以避免不必要的重新渲染。
表单组件
设置了 value 的 <input> 是一个受限组件。 
对于受限的 <input>,渲染出来的 HTML 元素始终保持 value 属性的值。
如果想响应更新用户输入的值,就得使用 onChange 事件
没有设置 value(或者设为 null) 的 <input> 组件是一个不受限组件。
如果想给组件设置一个非空的初始值,可以使用 defaultValue 属性。
<input type="text" />
<input type="text" defaultValue="Hello!" />
<input type="radio" name="opt" defaultChecked /> Option 1
<input type="radio" name="opt" /> Option 2
            
<textarea name="description" value="This is a description." />
<select value="B">
<option value="A">Apple</option>
<option value="B">Banana</option>
<option value="C">Cranberry</option>
</select>
给 value 属性传递一个数组,可以选中多个选项:<select multiple={true} value={['B', 'C']}>。
表单事件
onChange onInput onSubmit
Component Lifecycle(组件生命周期)
        Mounting:已插入真实 DOM
        Updating:正在被重新渲染
        Unmounting:已移出真实 DOM
mount(挂载)
    getInitialState() 
    object在组件被挂载之前调用。
    状态化的组件应该实现这个方法,返回初始的state数据。
    
    componentWillMount()
    在挂载发生之前立即被调用。
    
    componentDidMount()在挂载结束之后马上被调用。
    需要DOM节点的初始化操作应该放在这里。
    
    forceUpdate()
    挂载的复合组件
    当你知道一些很深的组件state已经改变了的时候,可以在该组件上面调用,而不是使用this.setState()。
update(更新)
    componentWillReceiveProps(object nextProps)
    当一个挂载的组件接收到新的props的时候被调用。
    该方法应该用于比较this.props和nextProps,然后使用this.setState()来改变state。
    
    shouldComponentUpdate(object nextProps, object nextState) boolean当组件做出是否要更新DOM的决定的时候被调用。实现该函数,优化this.props和nextProps,以及this.state和nextState的比较,如果不需要React更新DOM,则返回false。
    
    componentWillUpdate(object nextProps, object nextState)在更新发生之前被调用。你可以在这里调用this.setState()。
    
    componentDidUpdate(object prevProps, object prevState)
    在更新发生之后调用。
unmount(移除)
    componentWillUnmount()
    在组件移除和销毁之前被调用。清理工作应该放在这里。
ReactDOM.findDOMNode
替代 getDOMNode
DOMElement findDOMNode(ReactComponent component)
如果组件已经挂载到了 DOM 上,该方法返回相应的本地浏览器 DOM 元素。
从 DOM 中读取值的时候,该方法很有用,比如获取表单字段的值和做一些 DOM 操作。
当 render 返回 null 或者 false 的时候,findDOMNode 返回 null。
ref
一种非常特殊的属性,可以用来绑定到 render() 输出的任何组件上去。这个特殊的属性允许引用 render() 返回的相应的支撑实例( backing instance )。这样就可以确保在任何时间总是拿到正确的实例。
1、绑定一个 ref 属性到 render 返回的东西上面去,eg:
  <input ref="myInput" />
2、在其它代码中(典型地事件处理代码),通过 this.refs 获取支撑实例( backing instance ),eg:
  this.refs.myInput
通过调用 this.refs.myInput.getDOMNode() 直接获取到组件的 DOM 节点。
The ref Callback Attribute
 
 render: function() {
    return (
      <TextInput
        ref={function(input) {
          if (input != null) {
            input.focus();
          }
        }} />
    );
  },
  
  The ref String Attribute 
  
  <input ref="myInput" />
  
var input = this.refs.myInput;
var inputValue = input.value;
var inputRect = input.getBoundingClientRect();
  
Namespaced Components
var Form = MyFormComponent; var FormRow = Form.Row; var FormLabel = Form.Label; var FormInput = Form.Input; var App = ( <Form> <FormRow> <FormLabel /> <FormInput /> </FormRow> </Form> ); 简化: var Form = MyFormComponent; var App = ( <Form> <Form.Row> <Form.Label /> <Form.Input /> </Form.Row> </Form> ); 实现: var MyFormComponent = React.createClass({ ... }); MyFormComponent.Row = React.createClass({ ... }); MyFormComponent.Label = React.createClass({ ... }); MyFormComponent.Input = React.createClass({ ... }); 编译效果: var App = ( React.createElement(Form, null, React.createElement(Form.Row, null, React.createElement(Form.Label, null), React.createElement(Form.Input, null) ) ) );
触摸事件
为了使触摸事件生效,在渲染所有组件之前调用 React.initializeTouchEvents(true)。
initializeTouchEvents(boolean shouldUseTouch)
onTouchCancel onTouchEnd onTouchMove onTouchStart
鼠标事件
onClick onDoubleClick
onDrag onDragEnd onDragEnter onDragExit onDragLeave
onDragOver onDragStart 
onDrop
onMouseDown onMouseEnter onMouseLeave
onMouseMove onMouseOut onMouseOver onMouseUp
ReactDOM.render
好像是替代了React.render
render(
  ReactElement element,
  DOMElement container,
  [function callback]
)
Render a ReactElement into the DOM in the supplied container and return a reference to the component (or returns null for stateless components).
If the ReactElement was previously rendered into container, this will perform an update on it and only mutate the DOM as necessary to reflect the latest React component.
If the optional callback is provided, it will be executed after the component is rendered or updated.
Note:
ReactDOM.render() controls the contents of the container node you pass in. Any existing DOM elements inside are replaced when first called. Later calls use React’s DOM diffing algorithm for efficient updates.
ReactDOM.render() does not modify the container node (only modifies the children of the container). In the future, it may be possible to insert a component to an existing DOM node without overwriting the existing children.
ReactDOM.render() currently returns a reference to the root ReactComponent instance. However, using this return value is legacy and should be avoided because future versions of React may render components asynchronously in some cases. If you need a reference to the root ReactComponent instance, the preferred solution is to attach a callback ref to the root element.
                    
                
                
            
        
浙公网安备 33010602011771号