- React基础
//ReactDOM.render(reactWhat,domWhere)在浏览器中渲染应用的一种途径
//React.DOM表示预定义好的HTML元素集合
//React.DOM.h1(attributes,children)表示一个预定义的React 组件
//h1()第一个参数接收一个对象,用于指定该组件的任何属性(比如id属性,三个特殊属性class:className,for:htmlFor,style:对象形式赋值)。
//h1()第二个参数定义了该组件的子元素(Hello world!)
//document.getElementById("app") 方法访问DOM 节点,告诉React 需要把应用渲染在页面的哪个部分
ReactDOM.render(React.DOM.h1({
id: 'my-heading'
}, 'Hello world!'), document.getElementById('app'));
// JSX版本
ReactDOM.render(
<h1 id="my-heading" >
<span><em>Hell < /em>o</span > world!
< /h1>,
document.getElementById('app')
);
- 自定义新组件
//自定义新组件
var Component = React.createClass({
//该对象需要包含一个名为render() 的方法来显示组件
render: function () {
//该方法必须返回一个React 组件,不能只返回文本内容。
return React.DOM.span(null, 'I\'m so custom');
}
});
//使用自定义组件
ReactDOM.render(
//React.createElement() 是创建组件“实例”的方法之一
React.createElement(Component),
//如果你想创建多个实例,还有另一种途径,就是使用工厂方法:React.createFactory(Component);
document.getElementById('app')
);
- props和propTypes
//自定义的组件可以接收属性,所有属性都可以通过this.props对象获取
var Component = React.createClass({
//propTypes是可选的,声明组件需要接收的属性列表及其对应类型
propTypes: {
//清晰地指明了name 属性是一个必须提供的字符串值
name: React.PropTypes.string.isRequired,
middleName: React.PropTypes.string,
},
//getDefaultProps() 方法返回一个对象,并为每个可选属性(不带.isRequired的属性)提供了默认值。
getDefaultProps: function () {
return {
middleName: 'chris'
};
},
render: function () {
//请把this.props 视作只读属性。从父组件传递配置到子组件时,属性非常重要
return React.DOM.span(null, 'My name is ' + this.props.name);
}
});
ReactDOM.render(
React.createElement(Component, {
name: 'Bob'
}),
document.getElementById('app')
);
- 带状态的文本框组件
var TextAreaCounter = React.createClass({
propTypes: {
text: React.PropTypes.string,
},
getDefaultProps: function () {
return {
text: '',
};
},
// 无状态版本
render: function () {
return React.DOM.div(null,
//文本框使用了defaultValue 属性,而不是你在常规HTML 中习惯使用的文本子元素
React.DOM.textarea({
defaultValue: this.props.text,
}),
React.DOM.h3(null, this.props.text.length)
);
},
// 有状态版本(状态state负责组件内部数据的维护)
_textChange: function (ev) {//数据发生改变时(即用户在文本框中输入内容时),组件可以通过一个事件监听器更新state
this.setState({//改变state 必须使用this.setState() 方法。该方法接收一个对象参数,并把对象与this.state 中已存在的数据进行合并
text: ev.target.value,
});
},
getInitialState: function () {//在初始化时,定义state中需要包含的属性,以保证可以通过this.state.text访问属性
return {
text: this.props.text,
};
},
render: function () {
return React.DOM.div(null,
//文本框使用了defaultValue 属性,而不是你在常规HTML 中习惯使用的文本子元素
React.DOM.textarea({
value: this.state.text,
//React 使用了合成事件来消除浏览器之间的不一致情况,React 在事件处理中使用驼峰法命名。
//当用户输入时触发。而不是像原生DOM 事件那样,在用户结束输入并把焦点从输入框移走时才触发。
onChange: this._textChange,
}),
React.DOM.h3(null, this.state.text.length)
);
}
});
// 使用自定义组件
ReactDOM.render(
React.createElement(TextAreaCounter, {
text: "Bob",
}),
document.getElementById("app")
);
- 从外部访问组件(谨慎使用)
var myTextAreaCounter = ReactDOM.render(
React.createElement(TextAreaCounter, {
defaultValue: "Bob",
}),
document.getElementById("app")
);
//设置了新的state 值
myTextAreaCounter.setState({ text: "Hello outside world!" });
//获取了React 创建的父元素DOM 节点的引用
var reactAppNode = ReactDOM.findDOMNode(myTextAreaCounter);
//获取DOM 结构中首个<div id="app"> 节点。这也是你让React 进行渲染的位置:
reactAppNode.parentNode === document.getElementById('app'); // true
//访问组件的属性和状态
myTextAreaCounter.props; // Object { defaultValue: "Bob"}
myTextAreaCounter.state; // Object { text: "Hello outside world!"}
- 中途改变属性
//这个方法会接收新属性对象,让你可以根据新属性设置state
componentWillReceiveProps: function(newProps) {
this.setState({
text: newProps.defaultValue,
});
};
生命周期方法
初始化
- getDefaultProps()
设置默认的props
,也可以用dufaultProps
设置组件的默认属性.
对于组件类来说只调用一次,该组件类的所有后续应用,getDefaultPops
将不会再被调用
- getInitialState()
在使用es6
的class语法时是没有这个钩子函数的,可以直接在constructor
中定义this.state
。
对于组件的每个实例来说,这个方法的调用有且只有一次,用来初始化每个实例的 state
,在这个方法里,可以访问组件的 this.props
。
getInitialState
和 getDefaultPops
的调用是有区别的,getDefaultPops
是对于组件类来说只调用一次,后续该类的应用都不会被调用,
而 getInitialState
是对于每个组件实例来讲都会调用,并且只调一次。
- componentWillMount()
组件初始化之后,首次渲染之前调用,以后组件更新不调用,整个生命周期只调用一次,是在render
方法调用之前修改 state
的最后一次机会。
- render()
react
最重要的步骤,创建虚拟dom
,进行diff
算法,更新dom
树都在此进行。此时就不能更改state
了。
该方法会创建一个虚拟DOM
,用来表示组件的输出。对于一个组件来讲,render
方法是唯一一个必需的方法。
render
方法需要满足下面几点:
(1)只能通过 this.props
和 this.state
访问数据(不能修改)
(2)可以返回 null
,false
或者任何React
组件
(3)只能出现一个顶级组件,不能返回一组元素
(4)不能改变组件的状态
(5)不能修改DOM
的输出
render
方法返回的结果并不是真正的DOM
元素,而是一个虚拟的表现,类似于一个DOM tree
的结构的对象。react
之所以效率高,就是这个原因。
- componentDidMount()
组件渲染之后调用,只调用一次。
该方法被调用时,已经渲染出真实的 DOM
,可以再该方法中通过 this.getDOMNode()
访问到真实的 DOM
(推荐使用 ReactDOM.findDOMNode()
)。
由于组件并不是真实的 DOM
节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM)
。只有当它插入文档以后,才会变成真实的 DOM
。有时需要从组件获取真实 DOM
的节点,这时就要用到 ref
属性:
var Area = React.createClass({
render: function () {
this.getDOMNode(); //render调用时,组件未挂载,这里将报错
return <canvas ref='mainCanvas' >
},
componentDidMount: function () {
var canvas = this.refs.mainCanvas.getDOMNode();
//这是有效的,可以访问到 Canvas 节点
}
});
需要注意的是,由于 this.refs.[refName]
属性获取的是真实 DOM
,所以必须等到虚拟 DOM
插入文档以后,才能使用这个属性,否则会报错。
更新
此时组件已经渲染好并且用户可以与它进行交互,比如鼠标点击,手指点按,或者其它的一些事件,导致应用状态的改变,你将会看到下面的方法依次被调用
- componentWillReceiveProps(nextProps)
组件的 props
属性可以通过父组件来更改,这时,componentWillReceiveProps
将来被调用。可以在这个方法里更新 state
,以触发 render
方法重新渲染组件。
componentWillReceiveProps: function(nextProps) {
if (nextProps.checked !== undefined) {
this.setState({
checked: nextProps.checked
})
}
}
- shouldComponentUpdate(nextProps, nextState)
react
性能优化非常重要的一环。
组件接受新的state
或者props
时调用,我们可以在此对比前后两个props
和state
是否相同。
如果相同,则返回false
阻止更新,因为相同的属性状态一定会生成相同的dom
树,这样就不需要创造新的dom
树和旧的dom
树进行diff
算法对比,节省大量性能
如果你确定组件的 props
或者state
的改变不需要重新渲染,可以通过在这个方法里通过返回 false
来阻止组件的重新渲染,返回 false
则不会执行 render
以及后面的 componentWillUpdate
,componentDidUpdate
方法。
返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。 可以在你确认不需要更新组件时使用。
该方法是非必须的,并且大多数情况下不会使用。
- componentWillUpdate(nextProps, nextState)
这个方法和 componentWillMount
类似,在组件接收到了新的 props
或者 state
即将进行重新渲染前,componentWillUpdate(object nextProps, object nextState)
会被调用。
注意此时可以修改state
,但最好不要在此方面里再去更新 props
或者 state
。
- render()
组件渲染
- componentDidUpdate()
这个方法和 componentDidMount
类似,在组件重新被渲染之后,componentDidUpdate(object prevProps, object prevState)
会被调用。可以在这里访问并修改 DOM
。
卸载
- componentWillUnmount()
组件将要卸载时调用,一些事件监听和定时器需要在此时清除。
// 组件卸载
React.unmountComponentAtNode(this.props.containerNode[0]);
网友评论