react
一、ReactDom.render()方法是react的最基本的方法,用于将模板转为HTML语言,并插入到指定的DOM节点里。
ReactDom.render(
<h1>Hello,world!</h1>,
document.getElementById('example')
)
二、JSX语法
上一节代码中,html标签直接写在javascript语言中,不加任何引号,这就是JSX语法,他允许HTML和javascript的混写
var names = ['Alice', 'Emily', 'Kate'];
ReactDOM.render(
<div>
{
names.map(function(name){
return <div>{name}</div>
})
}
</div>,
document.getElementById("example")
)
上面的代码体现了JSX的基本语法规则:遇到HTML标签(以<开头),就用HTML规则解析,遇到代码块(以{开头),就用javascript语法解析
JSX允许直接在模板中插入javascript变量,如果这个变量是一个数组,则会展开这个数组的所有成员
var arr = [
<h1>Hello world!</h1>,
<h2>React is awesome</h2>,
];
ReactDOM.render(
<div>{arr}</div>,
document.getElementById("example")
)
上面代码的arr变量是一个数组,结果JSX把它的所有成员添加到模板,运行结果如下:
三、组件
React将代码封装成组件(Component),然后像插入普通html标签一样,在网页中插入这个组件,React.createClass方法就用于生成一个组件类
var HelloMessage = React.createClass({
render: function(){
return <h1>Hello,{this.props.name}</h1>
}
})
ReactDOM.render(
<HelloMessage name="孙俪"/>,
document.getElementById("example")
)
上面代码,HelloMessage就是一个组件类,模板插入<HelloMessage />时,会自动生成一个HelloMessage的一个实例,所有组件类都必须有自己的render方法,用于输出组件
注意:组件类的第一个字母必须大写,否则会报错,比如:HelloMessage不能写成helloMessage。另外,组件类只能包含一个顶层标签,否则也会报错
var HelloMessage = React.createClass({
render: function(){
return <h1>Hello,{this.props.name}</h1>
<p>哈哈</p>
}
})
ReactDOM.render(
<HelloMessage name="孙俪"/>,
document.getElementById("example")
)
上面的代码会报错,因为组件类里面包含了两个顶层标签,h1 和 p。
组件的用法和原生的html标签完全一致,可以任意加入属性,比如,<HelloMessage name="Jone">组件加入了一个name属性,值为Jone,组件的属性可以在组件类的this.props对象上获取,比如,name属性就可以通过this.props.name读取。
在给组件类里的元素添加属性的时候,class属性需要写成className,for属性需要写成htmlFor,这是因为class和for都是javascript的保留字
四、this.props.children
this.props对象的属性和组件的属性一一对应,但是有一个例外,就是this.props.children属性。他表示组件的所有子节点
var NotesList = React.createClass({
render: function(){
return (
<ol>
{
React.Children.map(this.props.children,function(child){
return <li>{child}</li>
})
}
</ol>
);
}
})
ReactDOM.render(
<NotesList>
<span>hello</span>
<span>world</span>
</NotesList>,
document.body
)
上面代码的NoteList组件有两个span子节点,他们都可以通过this.props.children读取,运行结果如下
这里需要注意,this.props.children的值有三种可能:如果当前组件没有子节点,他就是undefined;如果有一个子节点,数据类型是object;如果有多个子节点,数据类型就是array。所以,处理this.props.children的时候要小心。例如下面的例子,
var NoteList = React.createClass({
render: function(){
return (
<ol>
{
this.props.children.map(function (child) {
return <li>{child}</li>
})
}
</ol>
);
}
});
ReactDOM.render(
<NoteList>
<span>工号</span>
</NoteList>,
document.body
)
上面的代码由于组件的子节点只有一个span元素,是个object类型,所以会报错
React提供一个工具方法React.Children来处理this.props.children。我们可以用React.Children.map来遍历子节点,而不用担心this.props.children的数据类型是undeifned还是object。
六、PropTypes
组件的属性可以接受任意值,字符串、对象、函数等等都可以。有时,我们需要一种机制,验证别人使用组件时,提供的参数是否符合要求。
组件类的PropTypes属性,就是用来验证组件实例的属性是否符合要求。
var MyTitle = React.createClass({
propTypes: {
title:React.PropTypes.string.isReguired,
},
render: function() {
return <h1>{this.props.title}</h1>
}
})
上面的MyTitle组件有一个title属性。PropTypes告诉React,这个title属性是必须的,而且他的值必须是字符串。现在,我们设置title属性的值是一个数值
var data=123;
ReactDOM.render(
<MyTitle title={data} />,
document.body
)
这样一来,title属性就不通过验证了。控制台会显示一行错误信息。
此外,getDefaultProps方法可以用来设置组件属性的默认值。
var MyTitle = React.createClass({
getDefaultProps: function(){
return {
title: 'Hello World'
};
},
render: function() {
return <h1> {this.props.title} </h1>
}
});
ReactDOM.render(
<MyTitle />,
document.body
)
上面代码会输出:"Hello World"。
六、获取真实的DOM节点
组件并不是真实的DOM节点,而是存在于内存之中的一种数据结构,叫做虚拟DOM。只有当他插入文档以后,才会变成真实的DOM。根据React的设计,所有的DOM变动,都先在虚拟DOM上发生,然后再将实际发生变动的部分,反映在真实DOM上,这种算法叫做DOM diff,它可以极大提高网页的性能表现。
但是,有时候需要从组建获取真实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>
);
}
})
ReactDOM.render(
<MyComponent></MyComponent>,
document.body
)
上面代码中,组建MyComponent的子节点有一个文本输入框,用于获取用户的输入。这时就必须获取真实的DOM节点,虚拟DOM是拿不到用户输入的。为了做到这一点,文本输入框必须有一个ref属性,然后this.refs.[refName]就会返回这个真实的DOM节点。
需要注意的是,由于this.refs.[refName]属性获取的是真实DOM,所以必须等到虚拟DOM插入文档之后,才能使用这个属性,否则会报错。上面代码中,通过为组件指定click事件的回调函数,确保了只有等到真实DOM发生Click事件之后,才会读取this.refs.[refName]属性。
七、this.state
组件免不了要与用户互动,React的一大创新,就是将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染UI
var LikeButton = React.createClass({
getInitialState: function() {
return {liked: false};
},
handleClick: function(event) {
this.setState({liked: !this.state.liked});
},
render: function() {
var text = this.state.liked ?'like':'haven\'t liked';
return (
<p onClick={this.handleClick}>
You {text} this. Click to toggle.
</p>
)
}
});
ReactDOM.render(
<LikeButton />,
document.body
)
上面代码是一个LikeButton组件,它的getInitialState方法用于定义初始状态,也就是一个对象,这个对象可以通过this.state属性读取,当用户点击组件,导致状态变化,this.setState方法就修改状态值,每次修改以后,自动调用this.render方法,再次渲染组件。
由于this.props和this.state都用于描述组件的特性,可能会产生混淆,一个简单的区分方法是,this.props表示哪些一旦定义,就不再改变的特性,而this.state是会随着用户互动而产生变化的特性。