MVC是模型(model)-视图(view)-控制器(contraller)
React.js是一个帮助构建页面UI的库,React的组件就相当于MVC里面的view。React帮助我们将界面分成各个独立的小块,每一个块就是组件,这些组件之间可以组合,嵌套,就成了我们的页面。
React.js不是一个框架,它只是一个库,它只提供UI(view)层面的解决方案。在实际项目中,需要结合其它的库,如Redux、React-router来协助提供完整的解决方法。
一、HTML模版
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"></script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
</script>
</body>
</html>
上面的模版中type="text/babel"
这是因为 React 独有的 JSX 语法,跟 JavaScript 不兼容。凡是使用 JSX 的地方,都要加上 type="text/babel" 。
上面代码一共使用了三个库:
- react.js
是React的核心库 - react-dom.js
是提供与DOM相关的功能 - Browser.js
是将JSX语法转为JavaScript语法,这一步很消耗时间,实际上线的时候,应该放到服务器。
ReactDOM.render()
ReactDOM.render是React的最基本的方法,用于将模版转为HTML语言,并插入到对应的DOM节点。
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
React元素渲染
元素是构成React应用的最小单位,它用于描述屏幕上输出的内容。
ReactDOM.render()
将其内容渲染在页面上。
<div id="example"></div>
<script type="text/babel">
const element=<h1>Hello,world!</h1>;
ReactDOM.render(
element,
document.getElementById('example')
);
</script>

更新元素渲染
React元素都是不可变的,当元素被创建后,就无法改变其内容或者属性的。
目前更新界面的唯一方法是创建一个新的元素,然后将它传入ReactDOM.render()方法。
<div id="example"></div>
<script type="text/babel">
function tick(){
const element=(
<div>
<h1>Hello, world!</h1>
<h2>现在是{new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(
element,
document.getElementById('example')
);
}
setInterval(tick,1000);
</script>

setInterval()
方法,每秒钟调用一次ReactDOM.render()。我们可以将要展示的部分封装起来
function Clock(props){
return (
<div>
<h1>Hello world!</h1>
<h2>现在是{props.date.toLocaleTimeString()}.</h2>
</div>
)
}
function tick(){
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById("example")
)
}
setInterval(tick,1000);
</script>
除了函数外我们还可以创建一个React.Component的ES6类,该类封装了要展示的元素,需要注意的是在render()方面中,需要使用this.props替换props.
class Clock extends React.Component{
render(){
return (
<div>
<h1>Hello, world!</h1>
<h2>现在是{this.props.date.toLocaleTimeString()}</h2>
</div>
)
}
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('example')
)
}
setInterval(tick,1000);
JSX语法
ReactDOM.render(
<div>
{
names.map(function (name) {
return <div>Hello, {name}!</div>
})
}
</div>,
document.getElementById('example')
);
上面代码体现了 JSX 的基本语法规则:遇到 HTML 标签(以 < 开头),就用 HTML 规则解析;遇到代码块(以 { 开头),就用 JavaScript 规则解析。
- JSX中不能使用if-else
ReactDOM.render(
<div>
<h1>{i == 1 ? 'True!' : 'False'}</h1>
</div>
,
document.getElementById('example')
);
React推荐使用内联样式,我们可以使用camelCase语法来设置内联样式,React会在指定元素数字后面自动添加px。
let myStyle={
fontSize:100,
color:'#FF0000'
};
ReactDOM.render(
<div>
<h1 style={myStyle}>Hello World!</h1>
</div>,
document.getElementById('example')
);
注释
注释需要写在花括号中。
{/*注释...*/}
数组
JSX允许在模版中插入数组,数组会自动展开所有成员。
let arr=[
<h1>Hello</h1>,
<h2>world</h2>
];
ReactDOM.render(
<div>
{arr}
</div>,
document.getElementById('example')
);
独立文件
我们可以把React JSX代码可以放在一个独立的文件,在HTML中引入该JS。
React组件
1、定义一个组件
- 可以使用函数定义一个组件
function HelloMessage(props) {
return <h1>Hello World!</h1>;
}
- 可以使用ES6 class来定义一个组件
class Welcome extends React.Component {
render() {
return <h1>Hello World!</h1>;
}
}
2、为用户自定义的组件
const element=<Welcome />;
注意:原生HTML元素名以小写字母开头,而自定义的React类名以大写字母开头,比如HelloMessage
不能写成helloMessage
。除此之外还需要注意组件类只能包含一个顶层标签,否则也能报错。
-
如果需要传递参数
image.png
注意:在添加属性时,class属性需要写成className,for属性需要写成htmlFor,这是因为class和for是js的保留字。
复合组件
可以创建多个组件来合成一个组件,即把组件的不同功能点进行分离。
function Name(props){
return <h1>网站名称:{props.name}</h1>;
}
function URL(props){
return <h1>网站地址:{props.url}</h1>;
}
function NickName(props){
return <h1>网站小名:{props.nickname}</h1>;
}
function App(){
return (
<div>
<Name name="百度"/>
<URL url="http://www.baidu.com"/>
<NickName nickname="百"/>
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('example')
);
App组件使用了Name,Url,NickName组件来输出对应的信息。
React State(状态)
React把组件看成是一个状态机。通过与用户的交互,实现不同状态,然后渲染UI,让用户界面和数据保持一致。
React中,只需要更新组件的state,然后根据新的state重新渲染用户界面(不需要操作DOM)
示例:在render()方法中使用this.state来修改当前时间。
class Clock extends React.Component{
constructor(props){
super(props);
this.state={date:new Date()}
}
componentDidMount(){
this.timeId=setInterval(
()=>this.tick(),
1000
);
}
componentWillUnmount(){
clearInterval(this.timeId);
}
tick(){
this.setState({
date:new Date()
});
}
render(){
return(
<div>
<h1>Hello world!</h1>
<h2>现在是{this.state.date.toLocaleTimeString()}</h2>
</div>
)
}
}
ReactDOM.render(
<Clock />,
document.getElementById('example')
)
在具有许多组件的应用程序中国,在销毁时释放组件所占用的资源非常重要。
每当Clock组件第一次加载到DOM中的时候,我们都想生成定时器,这在React中被称为挂载。
同样,每当Clock生成的这个DOM被移除的时候,我们也会想要清除定时器,这在React中被称为卸载,我们可以在组件类上声明特殊的方法,当组件挂载或卸载时,来运行一些代码,如代码中的componentDidMount() ,componentWillUnmount()。
componentDidMount() ,componentWillUnmount()的方法被称作生命周期钩子。
在组件输出到 DOM 后会执行 componentDidMount() 钩子,我们就可以在这个钩子上设置一个定时器。
this.timerID 为计算器的 ID,我们可以在 componentWillUnmount() 钩子中卸载计算器。
React Props
state和props主要的区别在于props是不可变的,而state可以根据与用户交互来改变,这就是为什么有些容器组件需要定义state来更新和修改数据,而自组建只能通过props来传递数据。
Props示例
function HelloMessage(props){
return <h1>Hello {props.name}!</h1>
}
const element=<HelloMessage name='Runoob'/>;
ReactDOM.render(
element,
document.getElementById('example')
)

上面代码中的name属性通过this.props.name来获取。
可以通过组件类的defaultProps属性为props设置默认值。
function HelloMessage(props){
return <h1>Hello {props.name}!</h1>
}
HelloMessage.defaultProps={
name:'Tom'
}
const element=<HelloMessage />;
ReactDOM.render(
element,
document.getElementById('example')
)
State和Props
我们可以在父组件中设置state,并通过在子组件上使用props将其传递到子组件上。在render函数中,我们设置name和site来获取父组件传递过来的数据。
class WebSite extends React.Component{
constructor(){
super();
this.state={
name:"百度",
site:"http://www.baidu.com"
}
}
render(){
return(
<div>
<Name name={this.state.name} />
<Link site={this.state.site} />
</div>
)
}
}
class Name extends React.Component{
render(){
return(
<h1>{this.props.name}</h1>
)
}
}
class Link extends React.Component{
render(){
return(
<a href={this.props.site}>{this.props.site}</a>
)
}
}
ReactDOM.render(
<WebSite />,
document.getElementById('example')
)
Props验证
Props验证使用propTypes,它可以保证我们的应用组件被真确使用。
以下示例创建一个myTitle组件,属性title是必须的且是字符串,非字符串类型会自动转换为字符串。
var title="菜鸟教程";
class Mytitle extends React.Component{
render(){
return(
<h1>Hello,{this.props.title}</h1>
)
}
}
Mytitle.propTypes = {
title: PropTypes.string
}
ReactDOM.render(
<Mytitle title={title}/>,
document.getElementById('example')
)
React事件处理
React元素的事件处理和DOM元素相似,但是有一点语法上的不同。
- React事件绑定属性的命名采用驼峰式写法,而不是小写。
- 如果采用JSX的语法你需要传入一个函数作为事件处理函数,而不是一个字符串。
HTML 通常写法是:
<button onclick="activateLasers()">
激活按钮
</button>
React 中写法为:
<button onClick={activateLasers}>
激活按钮
</button>
示例
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// 这边绑定是必要的,这样 `this` 才能在回调函数中使用
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('example')
);
React条件渲染
在React中,可以创建不同的组件来封装需要的行为,然后还可以根据应用的状态变化只渲染其中的一部分。
React中的条件渲染和JavaScript中的一致,使用JavaScript操作符if或者条件运算符来创建表示当前状态的元素,然后让React根据他们来更新UI。
两个组件:
function UserGreeting(props){
return <h1>欢迎回来</h1>
}
function GuestGreeting(props){
return <h1>请先注册。</h1>
}
创建一个Greeting组件,根据用户是否登陆来显示其中之一。
function UserGreeting(props){
return <h1>欢迎回来</h1>
}
function GuestGreeting(props){
return <h1>请先注册。</h1>
}
function Greeting(props){
const isLoggedIn=props.isLoggedIn;
if(isLoggedIn){
return <UserGreeting/>
}
return <GuestGreeting/>
}
ReactDOM.render(
<Greeting isLoggedIn={true}/>,
document.getElementById('example')
)
元素变量
可以使用变量来存储元素,它可以帮助我们有条件的渲染组件的一部分,而输出的其他部分不会改变。
创造一个名为LoginControl的有状态的组件。
它会根据当前的状态来渲染<LoginButton/>或<LogoutButton/>,它也将渲染前面的例子中的<Greeting/>.
function UserGreeting(props){
return <h1>欢迎回来</h1>
}
function GuestGreeting(props){
return <h1>请先注册。</h1>
}
function Greeting(props){
const isLoggedIn=props.isLoggedIn;
if(isLoggedIn){
return <UserGreeting/>
}
return <GuestGreeting/>
}
function LoginButton(props){
return (
<button onClick={props.onClick}>登陆</button>
)
}
function LogoutButton(props) {
return (
<button onClick={props.onClick}>
退出
</button>
);
}
class LoginControl extends React.Component{
constructor(props){
super(props);
this.handleLoginClick=this.handleLoginClick.bind(this);
this.handleLogoutClick=this.handleLogoutClick.bind(this);
this.state={isLoggedIn:false};
}
handleLoginClick(){
this.setState({
isLoggedIn:true
})
}
handleLogoutClick(){
this.setState({
isLoggedIn:false
});
}
render(){
const isLoggedIn=this.state.isLoggedIn;
let button=null;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
return(
<div>
<Greeting isLoggedIn={isLoggedIn}/>
{button}
</div>
)
}
}
ReactDOM.render(
<LoginControl/>,
document.getElementById('example')
)
与运算符&&
可以通过用花括号包裹代码在JSX中嵌入任何表达式,也包括js的逻辑与.
function Mailbox(props){
const unreadMessage=props.unreadMessage;
return (
<div>
<h1>Hello!</h1>
{unreadMessage.length>0 && <h2>您有{unreadMessage.length}条未读信息。</h2>}
</div>
)
}
const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
<Mailbox unreadMessage={messages}/>,
document.getElementById('example')
)
在js中,true&&expression,而false && expression总是返回false.因此,如果条件是true,&&右侧的元素就会被渲染,如果是false,React会忽略并跳过它。
阻止组件渲染
在极少数的情况下,可能希望隐藏组件,让render方法返回null而不是它的渲染解决既可以实现。
function WarningBanner(props) {
if (!props.warn) {
return null;
}
return (
<div className="warning">
警告!
</div>
);
}
class Page extends React.Component{
constructor(props){
super(props);
this.state={showWarning:true}
this.handleToggleClick=this.handleToggleClick.bind(this)
}
handleToggleClick() {
this.setState(prevState => ({
showWarning: !prevState.showWarning
}));
}
render() {
return (
<div>
<WarningBanner warn={this.state.showWarning} />
<button onClick={this.handleToggleClick}>
{this.state.showWarning ? '隐藏' : '显示'}
</button>
</div>
);
}
}
ReactDOM.render(
<Page />,
document.getElementById('example')
);
React列表&&key
可以使用map()方法创建列表
const numbers=[1,2,3,4,5];
const listItems=numbers.map((number)=>
<li>{number}</li>
);
ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById('example')
)

重构
function NumberList(props){
const numbers=props.numbers;
const listItems=numbers.map((number)=><li key={number.toString()}>{number}</li>);
return(
<ul>{listItems}</ul>
)
}
const numbers=[1,2,3,4,5];
ReactDOM.render(
<NumberList numbers={numbers}/>,
document.getElementById('example')
)
keys
Keys 可以在 DOM 中的某些元素被增加或删除的时候帮助 React 识别哪些元素发生了变化。因此你应当给数组中的每一个元素赋予一个确定的标识。
当元素没有确定的 id 时,你可以使用他的序列号索引 index 作为 key
React组件API
- 设置状态:setState
- 替换状态: replaceState
- 设置属性: setProps
- 替换属性: replaceProps
- 强制更新: forceUpdate
- 获取DOM节点: findDOMNode
- 判断组件挂载状态: isMounted
class Counter extends React.Component{
constructor(props) {
super(props);
this.state = {clickCount: 0};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(function(state) {
return {clickCount: state.clickCount + 1};
});
}
render () {
return (<h2 onClick={this.handleClick}>点我!点击次数为: {this.state.clickCount}</h2>);
}
}
ReactDOM.render(
<Counter />,
document.getElementById('example')
);
React组件生命周期
- Mounting:已插入真实DOM
- Updating:正在被重新渲染
- Unmounting:已移出真实DOM
React Ajax
React 组件的数据可以通过 componentDidMount 方法中的 Ajax 来获取,当从服务端获取数据时可以将数据存储在 state 中,再用 this.setState 方法重新渲染 UI。
当使用异步加载数据时,在组件卸载前使用 componentWillUnmount 来取消未完成的请求。
class UserGist extends React.Component{
constructor(props){
super(props);
this.state={username:'',lastGistUrl:''}
}
componentDidMount(){
this.serverRequest=$.get(this.props.source,function(result){
var lastGistUrl=result[0];
this.setState({
username:lastGistUrl.owner.login,
lastGistUrl:lastGistUrl.html_url
});
}.bind(this));
}
componentWillUnmount(){
this.serverRequest.abort();
}
render(){
return(
<div>{this.state.username}用户最新的Gist共享地址:
<a href={this.state.lastGistUrl}>{this.state.lastGistUrl}</a></div>
)
}
}
ReactDOM.render(
<UserGist source="https://api.github.com/users/octocat/gists" />,
document.getElementById('example')
)
表单与事件
在 HTML 当中,像 <input>, <textarea>, 和 <select> 这类表单元素会维持自身状态,并根据用户输入进行更新。但在React中,可变的状态通常保存在组件的状态属性中,并且只能用 setState() 方法进行更新。
class HelloMessage extends React.Component{
constructor(props){
super(props);
this.state={value:'Hello world'}
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}/>
<h4>{value}</h4>
</div>
)
}
}
ReactDOM.render(
<HelloMessage />,
document.getElementById('example')
)
通过onchange事件来监听input的变化,并修改state
在组件上使用表单,onChange方法将出发state的跟新并将更新的 值传递到子组件的输入框的value上来重新渲染界面。
Select下拉菜单
在React中,不使用selected属性,而在根select标签上用value属性来表示选中项。
class FlavorForm extends React.Component{
constructor(props) {
super(props);
this.state = {value: 'coconut'};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event){
this.setState({value:event.target.value})
}
handleSubmit(event){
alert('Your favorite flavor is:'+this.state.value);
event.preventDefault();
}
render(){
return (
<form onSubmit={this.handleSubmit}>
<label>选择您最喜欢的网站
<select value={this.state.value} onChange={this.handleChange}>
<option value="gg">Google</option>
<option value="rn">Runoob</option>
<option value="tb">Taobao</option>
<option value="fb">Facebook</option>
</select>
</label>
<input type="submit" value="提交" />
</form>
)
}
}
ReactDOM.render(
<FlavorForm />,
document.getElementById('example')
);
多个表单
当有多个input元素时,可以通过给每个元素添加一个name属性,来让处理函数根据event.target.value
的值来选择做什么。
class Reservation extends React.Component{
constructor(props){
super(props);
this.state={
isGoing:true,
numberOfGuest:2
};
this.handleInputChange=this.handleInputChange.bind(this);
}
handleInputChange(event){
const target=event.target;
console.log(target);
const value=target.type==='checkbox'?target.checked:target.value;
console.log(value)
const name=target.name;
this.setState({
[name]:value
});
}
render(){
return (
<form>
<label>是否离开?
<input name="isGoing" type="checkbox" checked={this.state.isGoing} onChange={this.handleInputChange}>
</input>
</label>
<br />
<label>
访客数:
<input name="numberOfGuest" type="number"
value={this.state.numberOfGuest}
onChange={this.handleInputChange}>
</input>
</label>
</form>
)
}
}
ReactDOM.render(
<Reservation />,
document.getElementById('example')
);
React事件
通过onClick事件来修改数据
class HelloMessage extends React.Component{
constructor(props){
super(props);
this.state={
value:"Hello Runoob!"}
this.handleChange=this.handleChange.bind(this);
}
handleChange(event){
this.setState({
value:'菜鸟教程'
})
}
render(){
var value=this.state.value;
return (
<div>
<button onClick={this.handleChange}>点我</button>
<h4>{value}</h4>
</div>
)
}
}
ReactDOM.render(
<HelloMessage />,
document.getElementById('example')
);
当你需要从子组件更新父组件的state时,你需要在父组件通过创建事件句柄(handleChange),并作为prop(updateStateProp)传递到你的组件上。
class Content extends React.Component{
render(){
return (
<div>
<button onClick={this.props.updateStateProp}>点我</button>
<h4>{this.props.myDataProp}</h4>
</div>
)
}
}
class HelloMessage extends React.Component{
constructor(props){
super(props);
this.state={
value:'Hello Runoob!'
}
this.handleChange=this.handleChange.bind(this);
}
handleChange(event) {
this.setState({value: '菜鸟教程'})
}
render(){
var value=this.state.value;
return (
<div>
<Content myDataProp={value} updateStateProp={this.handleChange}/>
</div>
)
}
}
ReactDOM.render(
<HelloMessage />,
document.getElementById('example')
);
React Refs
React支持一种非常特殊的属性Ref,可以用来绑定到render()输出的任何组件上。
使用方法
绑定一个ref属性到render的返回值上:
<input ref="myInput" />
在其它代码中,通过this.refs获取支撑示例
var input=this.refs.myInput;
var inputValue=input.value;
var inputRect=input.getBoundingClientRect();
实例
可以通过使用this来获取当前的React组件,或使用ref来获取组件的引用。
class MyComponent extends React.Component{
handleClick(){
this.refs.myInput.focus();
}
render(){
return (
<div>
<input type="text" ref="myInput" />
<input type="button" value="点我" onClick={this.handleClick.bind(this)}/>
</div>
)
}
}
ReactDOM.render(
<MyComponent />,
document.getElementById('example')
);
网友评论