JSX语法:
1.ReactDOM.render:用于将模板转换为HTML语言,并插入指定的DOM节点;
语法规则:遇到 HTML 标签(以 <
开头),就用 HTML 规则解析,HTML 语言直接写在 JavaScript 语言之中,不加任何引号
<div id="example"></div>
<script type="text/babel">
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
</script>
2. 它允许 HTML 与 JavaScript 的混写
语法规则:遇到代码块(以 {
开头),就用 JavaScript 规则解析
var names = ['Alice', 'Emily', 'Kate'];
ReactDOM.render(
<div>
{
names.map(function (name) {
return <div>Hello, {name}!</div>
})
}
</div>,
document.getElementById('example')
);
结果为:hello Alice hello Emily hello Kate
3.直接在模板插入 JavaScript 变量,如果这个变量是一个数组,则会展开这个数组的所有成员
var arr = [
<h1>Hello world!</h1>,
<h2>React is awesome</h2>,
];
ReactDOM.render(
<div>{arr}</div>,
document.getElementById('example')
);
结果:Hello wold! React is awesome
二、组件:React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件
1.React.createClass用于生成一个组件类,所有组件类都必须有自己的 render
方法,用于输出组件
语法规则:
1)组件类的第一个字母必须大写,否则会报错:如HelloMessage写成helloMessage就会报错(例1)
2)组件类只能包含一个顶层标签(例2)
例1:
var HelloMessage = React.createClass({
render: function() {
return <h1>Hello {this.props.name}</h1>;
}
});
ReactDOM.render(
<HelloMessage name="John" />,
document.getElementById('example')
);
变量 HelloMessage
就是一个组件类,<HelloMessage />
会自动生成 HelloMessage
的一个实例
例2:
var HelloMessage = React.createClass({
render: function() {
return <h1>
Hello {this.props.name}
</h1><p>
some text
</p>;
}
});
这种写法就会报错:因为有两个顶层标签h1和p
3.给组件添加自定义属性:
语法规则:
1)为组件HelloMessage添加一个name属性
2)在组件类中使用this.props对象获取属性值
3)因为class和for是js的保留字,所以 clss需要写成:className,for需要写成:htmlFor
var HelloMessage = React.createClass({
render: function() {
return <h1>Hello {this.props.name}</h1>;
}
});
ReactDOM.render(
<HelloMessage name="John" />,
document.getElementById('example')
);
三、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
);
结果:1.hello 2.world
以上为: 通过this.props.children来读取NodeList组件的两个子节点span
注意1:this.props.children有三种可能值:
1)没有子节点时:undefined
2) 一个子节点时:Object
3) 多个子节点时:Array
注意2:可以使用React.Children.map来遍历子节点(更多方法官方文档)
四、PropTypes属性:就是用来验证组件实例的属性是否符合要求
注:组件的属性可以接受任意值,字符串、对象、函数等等都可以
var MyTitle = React.createClass({
propTypes: {
title: React.PropTypes.string.isRequired,
},
render: function() {
return <h1> {this.props.title} </h1>;
}
});
PropTypes
告诉 React,这个 title
属性是必须的,而且它的值必须是字符串。现在,我们设置 title
属性的值是一个数值就会报错。更多的PropTypes设置看官网
五、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 (virtual 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 />,
document.getElementById('example')
);
上面代码中,组件 MyComponent
的子节点有一个文本输入框,用于获取用户的输入。这时就必须获取真实的 DOM 节点,虚拟 DOM 是拿不到用户输入的。为了做到这一点,文本输入框必须有一个 ref
属性,然后 this.refs.[refName]
就会返回这个真实的 DOM 节点。
需要注意的是,由于 this.refs.[refName]
属性获取的是真实 DOM ,所以必须等到虚拟 DOM 插入文档以后,才能使用这个属性,否则会报错。上面代码中,通过为组件指定 Click
事件的回调函数,确保了只有等到真实 DOM 发生 Click
事件之后,才会读取 this.refs.[refName]
属性。
React 组件支持很多事件,除了 Click
事件以外,还有 KeyDown
、Copy
、Scroll
等
七、this.state:将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染 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.getElementById('example')
);
getInitialState:方法用于定义初始状态,也就是一个对象。
this.state:读取getInitialState返回的状态值 如:liked:false。
this.setState:修改状态值,每次修改以后自动调用this.render方法,在此渲染组件。
this.pros和this.setState的区别:
1)this.props:用于一旦定义就不再改变的特性;
2)this.setState:随着用户互动而产生变化的特性
九、表单:用户再表单输入的内容,属于用户跟组件互动,所以不能用this.props读取
var Input = React.createClass({
getInitialState: function() {
return {value: 'Hello!'};
},
handleChange: function(event) {
this.setState({value: event.target.value});
},
render: function () {
var value = this.state.value;
return (
<div>
<input type="text" value={value} onChange={this.handleChange} />
<p>{value}</p>
</div>
);
}
});
ReactDOM.render(<Input/>, document.body);
onChange:事件的回调函数
event.target.value:读取用户输入的值
注:像textarea、select、redio都属于这种情况
十:组件的声明周期:
1.组件的生命周期分为三个状态:
Mounting:以插入真实DOM
Updating:正在被重新渲染
Unmounting:已移除真实DOM
2.React为每个状态都提供了两种处理函数:
wil:函数正在进入状态之前调用
did:函数在进入状态之后调用
3.三种状态共计五种处理函数:
componentWillMount()
componentDidMount()
componentWillUpdate(object nextProps,object nextState)
componentDidUpdate(object prevProps,object prevState)
componentWillUnmount()
4.特殊状态:
componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
shouldComponentUpdate(object nectProps,object nextState):组件判断是否重新渲染时调用
var Hello = React.createClass({
getInitialState: function () {
return {
opacity: 1.0
};
},
componentDidMount: function () {
this.timer = setInterval(function () {
var opacity = this.state.opacity;
opacity -= .05;
if (opacity < 0.1) {
opacity = 1.0;
}
this.setState({
opacity: opacity
});
}.bind(this), 100);
},
render: function () {
return (
<div style={{opacity: this.state.opacity}}>
Hello {this.props.name}
</div>
);
}
});
ReactDOM.render(
<Hello name="world"/>,
document.body
);
注意:1)style的格式:style={{opacity: this.state.opacity}}
2) 注意setinterval()方法中,回调函数一定要加.bind(this)方法,原因是:在setInterval()中定义的回调函数,是在同步代码执行完后,随着事件触发来异步执行的,此时函数的上下文Context已经由定义该函数的Script文件变为全局变量,如果不通过bind(this)来指定由组件实例作为上下文的话,回调函数中的this会指向全局变量中的Window变量,显然不是我们想要的结果。
十一、Ajax
组件的数据来源,通常是通过 Ajax 请求从服务器获取,可以使用 componentDidMount
方法设置 Ajax 请求,等到请求成功,再用 this.setState
方法重新渲染 UI
var UserGist = React.createClass({
getInitialState: function() {
return {
username: '',
lastGistUrl: ''
};
},
componentDidMount: function() {
$.get(this.props.source, function(result) {
var lastGist = result[0];
if (this.isMounted()) {
this.setState({
username: lastGist.owner.login,
lastGistUrl: lastGist.html_url
});
}
}.bind(this));
},
render: function() {
return (
<div>
{this.state.username}'s last gist is
<a href={this.state.lastGistUrl}>here</a>.
</div>
);
}
});
ReactDOM.render(
<UserGist source="https://api.github.com/users/octocat/gists" />,
document.body
);
我们甚至可以把一个Promise对象传入组件
var RepoList = React.createClass({
getInitialState: function() {
return { 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: function() {
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) {
return (
<li>
<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.body
);
如果Promise对象正在抓取数据(pending状态),组件显示"正在加载";如果Promise对象报错(rejected状态),组件显示报错信息;如果Promise对象抓取数据成功(fulfilled状态),组件显示获取的数据