reactjs的一些笔记
1.使用虚拟DOM作为其不同的实现。同时可以由服务器node.js渲染,从而不需要过重的浏览器DOM支持。
1)获取属性的值用的是this.props.属性名
2)创建的组件名称首字母必须大写。
3)为元素添加css的class时,要用className。
4)组件的style属性的设置方式也值得注意,要写成style={{width: this.state.witdh}}。这是因为 React 组件样式是一个对象,所以第一重大括号表示这是 JavaScript 语法,第二重大括号表示样式对象。
5.组件状态
react将组件看做一个状态机,一旦组件的状态发生改变,react就会触发重新渲染UI(自动调用this.render)。通过this.state.XX来定义和设置用户自定义的状态。而getInitialState函数则是在组件初始化时执行,返回null或一个对象。例:
var InputState = React.createClass({
getInitialState:function(){
return {enable:false};
},
handleClick:function(event){
this.setState({enable:!this.state.enable});
},
render:function(){
return (
<p>
<input type="text" disabled={this.state.enable} />
<button onClick={this.handleClick}>Change State</button>
</p>
);
}
});
这里值得注意的几点如下:
1)getInitialState函数必须有返回值,可以是NULL或者一个对象。
2)访问state的方法是this.state.属性名。
3)变量用{}包裹,不需要再加双引号。
6.react组件的生命周期有3个
-
Mounting:已插入真实 DOM
-
Updating:正在被重新渲染
-
Unmounting:已移出真实 DOM
每个状态都有两种处理函数,will在进入状态前执行,did在进入之后执行,共五种处理函数:
-
componentWillMount()
-
componentDidMount()
-
componentWillUpdate(object nextProps, object nextState)
-
componentDidUpdate(object prevProps, object prevState)
-
componentWillUnmount()
此外,react还提供2种特殊状态的处理函数:
-
componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
-
shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用
7.this.props 对象的属性与组件的属性一一对应,但是有一个例外,就是 this.props.children 属性。它表示组件的所有子节点
这里需要注意, this.props.children 的值有三种可能:如果当前组件没有子节点,它就是 undefined ;如果有一个子节点,数据类型是 object ;如果有多个子节点,数据类型就是 array 。所以,处理 this.props.children 的时候要小心。
React 提供一个工具方法 React.Children 来处理 this.props.children 。我们可以用 React.Children.map 来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined 还是 object。更多的 React.Children 的方法,请参考
https://facebook.github.io/react/docs/top-level-api.html#react.children
8.组件的属性可以接受任意值,字符串、对象、函数等等都可以。有时,我们需要一种机制,验证别人使用组件时,提供的参数是否符合要求。
组件类的PropTypes属性,就是用来验证组件实例的属性是否符合要求
var MyTitle = React.createClass({
propTypes:{
title: React.PropTypes.string.isRequired,},
render:function(){return<h1>{this.props.title}</h1>;}});
这样,就规定了MyTitle的title属性是必须的,且类型为字符串。如果不符合要求,控制台就会报错。
更多的PropTypes设置,可以查看官方文档。
此外,getDefaultProps 方法可以用来设置组件属性的默认值。
getDefaultProps :function(){return{
title :'Hello World'};},
9.组件并不是真实的DOM节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM 。
但是,有时需要从组件获取真实 DOM 的节点,这时就要用到 ref 属性
var MyComponent = React.createClass({
handleClick:function(){
this.refs.myTextInput.focus();},
render:function(){return(<div><input type="text" ref="myTextInput"/><input type="button" value="Focus the text input" onClick={this.handleClick}/></div>);}});
文本输入框有一个 ref 属性,然后 this.refs.[refName] 就会返回这个真实的 DOM 节点。需要注意的是,由于 this.refs.[refName] 属性获取的是真实 DOM ,所以必须等到虚拟 DOM 插入文档以后,才能使用这个属性。
10.组件的构造规则跟函数或者对象的构造规则有异曲同工之妙,最大的共同点就是单一功能原则,即一个组件应该尽量只做一件事情,如果它的功能逐渐扩大就需要被拆分为更小的子组件。
13.常用的通知React 数据变化的方法是调用 setState(data, callback) 。这个方法会合并(merge) data 到 this.state,并重新渲染组件。渲染完成后,调用可选的callback 回调。大部分情况下不需要提供 callback ,因为 React 会负责把界面更新到最新状态。尝试把尽可能多的组件无状态化。 这样做能隔离 state,把它放到最合理的地方,也能减少冗余并,同时易于解释程序运作过程。常用的模式是创建多个只负责渲染数据的无状态(stateless)组件,在它们的上层创建一个有状态(stateful)组件并把它的状态通过 props 传给子级。这个有状态的组件封装了所有用户的交互逻辑,而这些无状态组件则负责声明式地渲染数据。
15.如果子级要在多个渲染阶段保持自己的特征和状态,在这种情况下,你可以通过给子级设置惟一标识的 key 来区分。当 React 校正带有 key 的子级时,它会确保它们被重新排序(而不是破坏)或者删除(而不是重用)。 务必把 key 添加到子级数组里组件本身上,而不是每个子级内部最外层 HTML 上。
时候一定确保你清楚到底做了什么,并且只在遇到明显性能问题的时候才使用它。不要低估 JavaScript 的速
度,DOM 操作通常才是慢的原因。
17. 传递Props的技巧,如果想把传入组件的全部props复制到对应的HTML元素上,<a {...this.props}>即可。有时候不需要传递所有属性,可使用 var { checked, ...other } = this.props; 再调用other即代表除了checked以外所有的props,而checked就是this,props.checked,可以直接使用,多个属性可以用逗号隔开。如果不使用 JSX,可以使用一些库来实现相同效果。Underscore 提供 _.omit 来过滤属性, _.extend 复制属性到新的对象。P60
var FancyCheckbox = React.createClass(
render: function() {
var checked = this.props.checked;
var other = _.omit(this.props, 'checked');
var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
return (
React.DOM.div(_.extend({}, other, { className: fancyClass }))
);
}
});
• 不可变的:一旦创建,集合不能在另一个时间点改变。
• 持久性:新的集合可以由从早先的集合和突变结合创建。在创建新的集合后,原来集合仍然有效。
• 结构共享:使用新的集合创建为与对原始集合大致相同的结构,减少了拷贝的最低限度,以实现空间效率和可接受的性能。如果新的集合等于原始的集合,则通常会返回原来的集合。
不变性使得跟踪更改方便;而变化将总是产生在新的对象,所以我们只需要检查的已经改变参考对象。
即原始的对象是不变的,每当对原始数据进行改变,会创建一个新的对象。
例:
var SomeRecord = Immutable.Record({ foo: null });
var x = new SomeRecord({ foo: 'bar' });
var y = x.set('foo', 'baz');
x === y; // false
26. React API
(1)React.createClass 不再赘述。
(2)React.createElement:
ReactElement createElement(
string/ReactClass type,
[object props],
[children ...]
)
创建并返回一个新的指定类型的 ReactElement。type 参数可以是一个 html 标签名字字符串(例如,“div”,“span”,等等),或者是 ReactClass (通过 React.createClass 创建的)。
factoryFunction createFactory(
string/ReactClass type
)
返回一个生成指定类型 ReactElements 的函数。比如 React.createElement,type 参数可以是一个 html 标签名字字符串(例如,“div”,“span”,等等),或者是 ReactClass 。
从 DOM 中移除已经挂载的 React 组件,清除相应的事件处理器和 state。如果在 container 内没有组件挂 载,这个函数将什么都不做。如果组件成功移除,则返回 true ;如果没有组件被移除,则返回 false 。
把组件渲染成原始的 HTML 字符串。该方法应该仅在服务器端使用。React 将会返回一个 HTML 字符串。你可以在服务器端用此方法生成 HTML,然后将这些标记发送给客户端,这样可以获得更快的页面加载速度,并且有利于搜索引擎抓取页面,方便做 SEO。
(6) string renderToStaticMarkup(ReactElement element)
和 renderToString 类似,除了不创建额外的 DOM 属性,例如 data-react-id ,因为这些属性仅在 React 内部使用。如果你想用 React 做一个简单的静态页面生成器,这是很有用的,因为丢掉额外的属性能够节省很多字节。
(7)React.isValidElement
boolean isValidElement(* object)判断对象是否是一个 ReactElement。
(8)initializeTouchEvents(boolean shouldUseTouch)
配置 React 的事件系统,使 React 能处理移动设备的触摸( touch )事件。
(9)React.ChildrenReact.Children
React.Children 为处理 this.props.children 这个封闭的数据结构提供了有用的工具。
详情见P82,有.map 、.forEach、.count、.only等用法。
27.ReactComponent
React 组件实例在渲染的时候创建。这些实例在接下来的渲染中被重复使用,可以在组件方法中通过 this 访问。唯一一种在 React 之外获取 React 组件实例句柄的方式就是保存 React.render 的返回值。在其它组件内,可以使用 refs 得到相同的结果。
(1)setState(object nextState[, function callback]))
合并 nextState 和当前 state。这是在事件处理函数中和请求回调函数中触发 UI 更新的主要方法。另外,也支持可选的回调函数,该函数在 setState 执行完毕并且组件重新渲染完成之后调用。
注:setState() 不会立刻改变 this.state ,而是创建一个即将处理的 state 转变。在调用该方法之后获取 this.state 的值可能会得到现有的值,而不是最新设置的值。
(3)forceUpdate([function callback])
如果 render() 方法从 this.props 或者 this.state 之外的地方读取数据,你需要通过调用 forceUpdate() 告诉 React 什么时候需要再次运行 render()。如果直接改变了 this.state ,也需要调用 forceUpdate()。
注:应该尽量避免使用forceUpdate的情况。
(4)bool isMounted()
如果组件渲染到了 DOM 中, isMounted() 返回 true。可以使用该方法保证 setState() 和 forceUpdate() 在异步场景下的调用不会出错。
(5)
28.render() 函数应该是纯粹的,也就是说该函数不修改组件 state,每次调用都返回相同的结果,不读写 DOM 信息,也不和浏览器交互(例如通过使用 setTimeout )。如果需要和浏览器交互,在 componentDidMount()中或者其它生命周期方法中做这件事。保持 render() 纯粹,可以使服务器端渲染更加切实可行,也使组件更容易被理解。
29.object statics
statics 对象允许你定义静态的方法,这些静态的方法可以在组件类上调用。
30. React 也提供了一些 DOM 里面不存在的属性。
• key :可选的唯一的标识器。当组件在 渲染 过程中被各种打乱的时候,由于差异检测逻辑,可能会被销毁后重新创建。给组件绑定一个 key,可以持续确保组件还存在 DOM 中。
• ref:参考这里 (页 0)。
• dangerouslySetInnerHTML :提供插入纯 HTML 字符串的功能,主要为了能和生成 DOM 字符串的库整合。
31.React的渲染策略
(1)若前后两个节点元素或者组件的类型不同,React会直接把他们当做不同的子树,甚至不会尝试计算出该渲染什么,直接从DOM中移除之前的节点,然后插入新的节点。
(2)比较两个DOM节点的时候,查看两者的属性,然后找出变化的属性。
(3)对于自定义组件,React决定2个自定义组件是相同的,利用新组件上的所有属性,然后再之前的组件实例上调用componetWill(Did)ReceiveProps()。现在,之前的组件的render(0被调用,然后差异算法重新比较新的状态和上一次的状态。
(4)为了完成子级更新,React同时遍历两个子级列表,当发现差异的时候,就产生一次DOM修改。
在开始处插入元素比较麻烦。React 发现两个节点都是 span,因此直接修改已有 span 的文本内容,然后在后面插入一个新的 span 节点。
renderA:<div><span>first</span></div>
renderB:<div><span>secon</span><span>first</span></div>=> [replaceAttribute textContent 'second'], [insertNode <span>first</span>]
为了解决这个问题,引入了一个可选的属性keys。如果指定了一个键值,React 就能够检测出节点插入、移除和替换,并且借助哈希表使节点移动复杂度为O(n)。
注:键值只需要在兄弟节点中唯一,而不是全局唯一。
var divStyle = {
color: 'white',
backgroundImage: 'url(' + imgUrl + ')',
WebkitTransition: 'all', // 注意这里的首字母'W'是大写
msTransition: 'all' // 'ms'是唯一一个首字母需要小写的浏览器前缀
};
React.render(Hello World!, mountNode);
33.通常,一个组件的子代(this.props.children)是一个组件的数组,即为数组类型,但是当只有一个子代的时候,this.props.children是一个单独的组件,而不是数组形式,这样就减少了数组的占用。
34.getInitialState里的props是一个反模式。详情见P118。
35.给DOM元素绑定React未提供的事件,比如想共用react和jquery的时候,在componentDidMount中 调用
component.addEventListener('xxx', this.handleResize) 绑定事件,在componentWillUnmount中removeEventListener()取消绑定。详情见P120
当执行同步请求的响应时,在更新 state 前, 一定要先通过 this.isMounted() 来检测组件的状态是否还是 mou
nted。