组件:
添加组件属性需要注意,class
属性需要写成className
,for
属性需要写成htmlFor
,这是因为class
和for
是JavaScript的保留字。
this.props.children
this.props
对象的属性与组件的属性一一对应,但是有一个例外,就是this.props.children
属性。它表示组件的所有子节点。
<body>
<div id="red">
<script type="text/babel">
class Message extends React.Component{
render(){
return(
<ol>
{
React.Children.map(this.props.children,function (child) {
return <li>{child}</li>
})
}
</ol>
)
}
}
ReactDOM.render(
<Message>
<span>我韩浩</span>
<span>会很好的</span>
</Message>,
document.getElementById('red')
);
</script>
</div>
</body>
- 需要注意:
this.props.children
的值有三种可能:如果当前组件没有子节点,它就是undefined
;如果有一个子节点,数据类型是object
;如果有多个子节点,数据类型就是array
.所以,处理this.props.children
的时候要小心。 - React提供一个工具方法
React.Children
来处理this.props.children
。我们可以用React.Children.map
来遍历子节点,而不用担心this.props.children
的数据类型是undefined
还是object
.
PropTypes
组件的属性可以接受任意值,字符串、对象、函数等等都可以。有时,我们需要一种机制,验证别人使用组件时,提供的参数是否符合要求。
组件类的PropTypes属性,就是用来验证组件实例的属性是否符合要求。
<body>
<div id="red">
<script type="text/babel">
var data = "你知道,我很喜欢你吗?";
class Message extends React.Component{
static good = {
title:PropTypes.string.isRequired,
};
render(){
return <h3>{this.props.title}</h3>
}
}
ReactDOM.render(
<Message title={data}/>,
document.getElementById('red')
)
</script>
</div>
</body>
获取真实的DOM节点
组件并不是真实的DOM节点,而是存在于内存之中的一种数据结构,叫做虚拟DOM(virtual DOM)。只有当它插入文档以后,才会变成真实的DOM。根据React的设计,所有的DOM变动,都先在虚拟DOM上发生,然后再将实际发生变动的部分,反映在真实DOM上,这种算法叫做DOM diff,它可以极大提高网页的性能表现。
但是,有时候需要从组件获取真实DOM的节点,这时就要用到ref属性。
<body>
<div id="red">
<script type="text/babel">
class MyTextInput extends React.Component{
constructor(props){
super(props);
this.myTextInput = React.createRef();
this.handleClick = this.handleClick.bind(this)
}
handleClick(){
this.myTextInput.current.focus();
}
render(){
return(
<div>
<input type="text" ref={this.myTextInput}/>
<input type="button" value="input" onClick={this.handleClick}/>
</div>
)
}
}
ReactDOM.render(
<MyTextInput/>,
document.getElementById('red')
)
</script>
</div>
</body>
this.state
组件免不了要与用户互动,React的一大创新,就是将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染UI.
<body>
<div id="red">
<script type="text/babel">
class LikeMessage extends React.Component{
constructor(props){
super(props);
this.state = {
liked:false
}
this.handClick = this.handClick.bind(this)
}
handClick(){
this.setState({liked:!this.state.liked})
}
render(){
var text = this.state.liked? '喜欢':'讨厌';
return(
<p onClick={this.handClick}>我{text}你</p>
)
}
}
ReactDOM.render(
<LikeMessage/>,
document.getElementById('red')
)
</script>
</div>
</body>
表单
用户在表单填入的内容,属于用户跟组件的互动,所以不能用this.props
读取。
<body>
<div id="red">
<script type="text/babel">
class Input extends React.Component{
constructor(props){
super(props);
this.state = {
value:'Hello'
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event){
this.setState({value:event.target.value});
}
render(){
var value = this.state.value;
return(
<div>
<input type="text" value={value} onChange={this.handleChange}/>
<p>{value}</p>
</div>
)
}
}
ReactDOM.render(
<Input/>,
document.getElementById('red')
)
</script>
</div>
</body>
上面代码中,文本输入框的值,不能用this.props.value
读取,而要定义一个onChange
事件的回调函数,通过event.target.value
读取用户输入的值。
textarea
元素、select
元素、radio
元素都属于这种情况。
组价的生命周期
组件的生命周期分成三个状态:
Mounting:已插入真实DOM
Updating:正在被重新渲染
Unmounting:已移出真实DOM
React为每个状态都提供了两种处理函数,will
函数在进入状态之前调用,did
函数在进入状态之后调用,三种状态共计五种处理函数。
componentWillMount()
componentDidMount()
componentWillUpdate(object nextProps, object nextState)
componentDidUpdate(object prevProps, object prevState)
componentWillUnmount()
此外,React还提供两种特殊状态的处理函数。
componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用
<body>
<div id="red">
<script type="text/babel">
class Hello extends React.Component{
constructor(props){
super(props);
this.state = {
opacity:1.0
};
}
componentDidMount(){
this.timer = setInterval(function () {
var opacity = this.state.opacity;
opacity -= 0.05;
if(opacity < 0.1){
opacity = 1.0
}
this.setState({
opacity:opacity
});
}.bind(this),100);
}
render(){
return(
<div style=>
我很好,{this.props.name}
</div>
)
}
}
ReactDOM.render(
<Hello name="你要好好的"/>,
document.getElementById('red')
)
</script>
</div>
</body>
Ajax
组件的数据来源,通常是通过Ajax请求从服务器获取,可以使用componentDidMount
方法设置Ajax请求,等到请求成功,再用this.setState
方法重新渲染UI
<body>
<div id="red">
<script type="text/babel">
class UserGist extends React.Component{
constructor(props){
super(props);
this.state = {
username:'',
lastGistUrl:''
}
}
componentDidMount(){
$.get(this.props.source,function (result) {
var lastGist = result[0];
this.setState({
username:lastGist.owner.login,
lastGistUrl:lastGist.html_url
});
}.bind(this));
}
render(){
return (
<div>
{this.state.username}'s 就是这个<a href={this.state.lastGistUrl}>here</a>
</div>
)
}
}
ReactDOM.render(
<UserGist source="https://api.github.com/users/octocat/gists"/>,
document.getElementById('red')
)
</script>
</div>
</body>
上面代码使用jQuery完成Ajax请求,这是为了便于说明。React本身没有任何依赖,完全可以不用jQuery,而使用其他库。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="../build/react.development.js"></script>
<script src="../build/react-dom.development.js"></script>
<script src="../build/babel.min.js"></script>
<script src="../build/prop-types.js"></script>
<script src="../build/jquery.min.js"></script>
</head>
<body>
<div id="red">
<script type="text/babel">
class RepoList extends React.Component{
constructor(props) {
super(props);
this.state = {
loading:true,
error:null,
data:null
}
}
componentDidMount(){
this.props.promise.then(
value => this.setState({loading:false,data:value}),
error => this.setState({loading:false,error:error})
);
}
render(){
if(this.state.loading){
return <span>Loading...</span>
}else if(this.state.error !== null){
return <span>Error:{this.state.error.message}</span>;
}else{
var repos = this.state.data.items;
var repoList = repos.map(function (repo,index){
return(
<li key={index}><a href={repo.html_url}>{repo.name}</a>({repo.stargazers_count} stars)<br/>{repo.description}</li>
)
})
return(
<main>
<h1>Most Popular JavaScript Projects in Github</h1>
<ol>{repoList}</ol>
</main>
)
}
}
}
ReactDOM.render(
<RepoList promise = {$.getJSON('https://api.github.com/search/repositories?q=javascript&sort=stars')}/>,
document.getElementById('red')
)
</script>
</div>
</body>
</html>