React 入门实例教程

一、安装

React 的安装包,可以到官网下载。

$ git clone git@github.com:ruanyf/react-demos.git

如果你没安装 git, 那就直接下载 zip 压缩包

二、HTML 模板

使用 React 的网页源码,结构大致如下。


<!DOCTYPE html>
<html>
<head>
<script src="../build/react.js"></script>//文件存放的路径
<script src="../build/react-dom.js"></script>
<script src="../build/browser.min.js"></script>
</head>
<body>
<div id="demo"></div>
<script type="text/babel">
// ** 代码 **
</script>
</body>
</html>

上面代码有两个地方需要注意。首先,最后一个 <script> 标签的 type 属性为 text/babel 。这是因为 React 独有的 JSX 语法,跟 JavaScript 不兼容。凡是使用 JSX 的地方,都要加上 type="text/babel" 。

其次,上面代码一共用了三个库: react.js 、react-dom.js 和 Browser.js ,它们必须首先加载(自行下载)。其中,react.js 是 React 的核心库,react-dom.js 是提供与 DOM 相关的功能,Browser.js 的作用是将 JSX 语法转为 JavaScript 语法,这一步很消耗时间,实际上线的时候,应该将它放到服务器完成。


$ babel src --out-dir build

上面命令可以将 src 子目录的 js 文件进行语法转换,转码后的文件全部放在 build 子目录。

三、ReactDOM.render()

ReactDOM.render 是 React 的最基本方法,用于将模板转为 HTML 语言,并插入指定的 DOM 节点。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>React</title>
<script src="../build/react.js"></script>
<script src="../build/react-dom.js"></script>
<script src="../build/browser.min.js"></script>
</head>
<body>
<div id="demo1" key="demo1"></div>
<script type="text/babel">
/**
* 1.ReactDOM.render()
*/
ReactDOM.render(
<h1 key="h1">Hello React!</h1>,
document.getElementById("demo1")
);
</script>
</body>
</html>

上面代码将一个 h1 标题,插入demo1节点。

四、JSX 语法

上一节的代码, HTML 语言直接写在 JavaScript 语言之中,不加任何引号,这就是 JSX 的语法,它允许 HTML 与 JavaScript 的混写。代码体现了 JSX 的基本语法规则:遇到 HTML 标签(以 < 开头),就用 HTML 规则解析;遇到代码块(以 { 开头),就用 JavaScript 规则解析。JSX 允许直接在模板插入 JavaScript 变量。如果这个变量是一个数组,则会展开这个数组的所有成员。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>React</title>
<script src="../build/react.js"></script>
<script src="../build/react-dom.js"></script>
<script src="../build/browser.min.js"></script>
</head>
<body>
<div id="demo2" key="demo2"></div>
   <div id="demo3" key="demo3"></div>
   <script type="text/babel">
        /**
* 2.JSX 语法
*/
let names = ['Alice', 'Emily', 'Kate'];
ReactDOM.render(
<div key="map">
{
names.map(function(name){
return <div key={"hello" + name}>Hello {name}!</div>
})
}
{
names.map((name) => {
return <div key={"hi" + name}>Hi {name}~</div>
})
}
</div>,
document.getElementById("demo2")
);
     /**
* 数组
*/
        let arr = [
<h1 key="h1">Hello Hello</h1>,
<h2 key="h2">React React</h2>
];
ReactDOM.render(
<div key="div">{arr}</div>,
document.getElementById("demo3")
);
</script>
</body>
</html>

五、组件

React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件。React.createClass 方法就用于生成一个组件类。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>React</title>
<script src="../build/react.js"></script>
<script src="../build/react-dom.js"></script>
<script src="../build/browser.min.js"></script>
</head>
<body>
<div id="demo4" key="demo4"></div>
   <script type="text/babel">
        /**
* 3.组件
*/
let Message = React.createClass({
render: function(){
return<div>
<h1 key="h1">Hi {this.props.name}</h1>
<h2 key="h2">Hello {this.props.age}</h2>
<h3 key="h3">Hello {this.props.address}</h3>
</div>
}
});
ReactDOM.render(
<Message key="message" name="John" age={18} address="吉林长春"/>,
document.getElementById("demo4")
);
</body>
</html>

上面代码中,变量 Message 就是一个组件类。模板插入 <Message />时,会自动生成 Message 的一个实例(下文的"组件"都指组件类的实例)。所有组件类都必须有自己的 render 方法,用于输出组件。

注意,组件类的第一个字母必须大写,否则会报错,比如Message不能写成message。另外,组件类只能包含一个顶层标签,否则也会报错。


var Message = React.createClass({
render: function() {
return <h1>
    Hello {this.props.name}
    </h1>
      <p>
    some text
    </p>;
   }
  });

上面代码会报错,因为Message组件包含了两个顶层标签:h1p

组件的用法与原生的 HTML 标签完全一致,可以任意加入属性,比如 <HelloMessage name="John"> ,就是 HelloMessage 组件加入一个 name 属性,值为 John。组件的属性可以在组件类的 this.props 对象上获取,比如 name 属性就可以通过 this.props.name 读取。上面代码的运行结果如下。

添加组件属性,有一个地方需要注意,就是 class 属性需要写成 className ,for 属性需要写成 htmlFor ,这是因为 class 和 for 是 JavaScript 的保留字。

六、this.props.children

this.props 对象的属性与组件的属性一一对应,但是有一个例外,就是 this.props.children 属性。它表示组件的所有子节点。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>React</title>
<script src="../build/react.js"></script>
<script src="../build/react-dom.js"></script>
<script src="../build/browser.min.js"></script>
</head>
<body>
<div id="demo5" key="demo5"></div>
<script type="text/babel">
/**
* 4.this.props.children
*/
let List = React.createClass({
render: function(){
return(
<ol key="ol">
{
React.Children.map(this.props.children, (child)=>{
console.log(this.props.children);
return <li key="li">{child}</li>
})
}
</ol>
);
}
});
ReactDOM.render(
<List key="list">
<span key="hello">Hello World</span>
<span key="react">Hello React</span>
</List>,
document.getElementById("demo5")
);
</script>
</body>
</html>

上面代码的 List 组件有两个 span 子节点,它们都可以通过 this.props.children 读取。

这里需要注意, this.props.children 的值有三种可能:如果当前组件没有子节点,它就是 undefined ;如果有一个子节点,数据类型是 object ;如果有多个子节点,数据类型就是 array 。所以,处理 this.props.children 的时候要小心。

React 提供一个工具方法 React.Children 来处理 this.props.children 。我们可以用 React.Children.map 来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined 还是 object。更多的 React.Children 的方法,请参考官方文档

七、PropTypes

组件的属性可以接受任意值,字符串、对象、函数等等都可以。有时,我们需要一种机制,验证别人使用组件时,提供的参数是否符合要求。

组件类的PropTypes属性,就是用来验证组件实例的属性是否符合要求。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>React</title>
<script src="../build/react.js"></script>
<script src="../build/react-dom.js"></script>
<script src="../build/browser.min.js"></script>
</head>
<body>
<div id="demo6" key="demo6"></div>
   <script type="text/babel">
        /**
* 5.PropTypes
*/
let Title1 = React.createClass({
propTypes: {
title: React.PropTypes.string.isRequired,
},
render: function(){
return <h1>{this.props.title}</h1>
}
});
/**
* data的类型要与Title1中title属性一致
* 否则会报:Warning: Failed propType: Invalid prop `title` of type `number` supplied to `Title1`, expected `string`.
* @type {string}
*/
let data = "Hello React";
ReactDOM.render(
<Title1 title={data}/>,
document.getElementById("demo6")
);
</script>
</body>
</html>

更多的PropTypes设置,可以查看官方文档

此外,getDefaultProps 方法可以用来设置组件属性的默认值。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>React</title>
<script src="../build/react.js"></script>
<script src="../build/react-dom.js"></script>
<script src="../build/browser.min.js"></script>
</head>
<body>
<div id="demo7" key="demo7"></div>
   <script type="text/babel">
        /**
* getDefaultProps
*/
let Title2 = React.createClass({
getDefaultProps: function(){
return{
title: "Hi React"
}
},
render: function(){
return <h1>{this.props.title}</h1>;
}
});
ReactDOM.render(
<Title2 />,
document.getElementById("demo7")
);
</script>
</body>
</html>

八、获取真实的DOM节点

组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM)。只有当它插入文档以后,才会变成真实的 DOM 。根据 React 的设计,所有的 DOM 变动,都先在虚拟 DOM 上发生,然后再将实际发生变动的部分,反映在真实 DOM上,这种算法叫做 DOM diff ,它可以极大提高网页的性能表现。

但是,有时需要从组件获取真实 DOM 的节点,这时就要用到 ref 属性。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>React</title>
<script src="../build/react.js"></script>
<script src="../build/react-dom.js"></script>
<script src="../build/browser.min.js"></script>
</head>
<body>
<div id="demo8" key="demo8"></div>
   <script type="text/babel">
        /**
* 6.获取真实的DOM节点
*/
let Component = React.createClass({
handleClick: function(){
this.refs.myTextInput.focus();
},
render: function(){
return (
<div key="component">
<input key="input1" type="text" ref="myTextInput"/>
<input key="input2" type="button" value="Focus the text input" onClick={this.handleClick}/>
</div>
);
}
});
ReactDOM.render(
<Component />,
document.getElementById("demo8")
);
</script>
</body>
</html>

上面代码中,组件 Component 的子节点有一个文本输入框,用于获取用户的输入。这时就必须获取真实的 DOM 节点,虚拟 DOM 是拿不到用户输入的。为了做到这一点,文本输入框必须有一个 ref 属性,然后 this.refs.[refName] 就会返回这个真实的 DOM 节点。

需要注意的是,由于 this.refs.[refName] 属性获取的是真实 DOM ,所以必须等到虚拟 DOM 插入文档以后,才能使用这个属性,否则会报错。上面代码中,通过为组件指定 Click 事件的回调函数,确保了只有等到真实 DOM 发生 Click 事件之后,才会读取 this.refs.[refName] 属性。

React 组件支持很多事件,除了 Click 事件以外,还有 KeyDown 、CopyScroll 等,完整的事件清单请查看官方文档

九、this.state

组件免不了要与用户互动,React 的一大创新,就是将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染 UI。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>React</title>
<script src="../build/react.js"></script>
<script src="../build/react-dom.js"></script>
<script src="../build/browser.min.js"></script>
</head>
<body>
<div id="demo9" key="demo9"></div>
   <script type="text/babel">
        /**
* 7.this.state
*/
let LikeButton = React.createClass({
getInitialState: function(){
return {liked: false};
},
handleClick: function(){
this.setState({liked: !this.state.liked});
},
render: function(){
let text = this.state.liked ? "like" : "haven\'t liked";
return(
<p key="p" onClick={this.handleClick}>
You {text} this.Click to toggle.
</p>
);
}
});
ReactDOM.render(
<LikeButton />,
document.getElementById("demo9")
);
</script>
</body>
</html>

上面代码是一个 LikeButton 组件,它的 getInitialState 方法用于定义初始状态,也就是一个对象,这个对象可以通过 this.state 属性读取。当用户点击组件,导致状态变化,this.setState 方法就修改状态值,每次修改以后,自动调用 this.render 方法,再次渲染组件。

由于 this.props 和 this.state 都用于描述组件的特性,可能会产生混淆。一个简单的区分方法是,this.props 表示那些一旦定义,就不再改变的特性,而 this.state 是会随着用户互动而产生变化的特性。

十、表单

用户在表单填入的内容,属于用户跟组件的互动,所以不能用 this.props 读取。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>React</title>
<script src="../build/react.js"></script>
<script src="../build/react-dom.js"></script>
<script src="../build/browser.min.js"></script>
</head>
<body>
<div id="demo10" key="demo10"></div>
   <script type="text/babel">
     1   /**
* 8.表单
*/
let Input = React.createClass({
getInitialState: function(){
return {value: "Hahaha!"};
},
handleChange: function(event){
this.setState({value: event.target.value});
},
render: function(){
let value = this.state.value;
return(
<div key="div">
<input key="input" type="text" value={value} onChange={this.handleChange}/>
<p key="p">{value}</p>
</div>
);
}
});
ReactDOM.render(
<Input />,
document.getElementById("demo10")
);
</script>
</body>
</html>

上面代码中,文本输入框的值,不能用 this.props.value 读取,而要定义一个 onChange 事件的回调函数,通过 event.target.value 读取用户输入的值。textarea 元素、select元素、radio元素都属于这种情况,更多介绍请参考官方文档

十一、组件的生命周期

生命周期:http://www.cnblogs.com/Michelle20180227/p/8525611.html

组件的生命周期分成三个状态:

  • 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):组件判断是否重新渲染时调用

这些方法的详细说明,可以参考官方文档。下面是一个例子。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>React</title>
<script src="../build/react.js"></script>
<script src="../build/react-dom.js"></script>
<script src="../build/browser.min.js"></script>
</head>
<body>
<div id="demo11" key="demo11"></div>
<script type="text/babel">
/**
* 9.组件的生命周期
*/
let Hi = React.createClass({
getInitialState: function(){
return {
opacity: 1.0
};
},
componentDidMount: function(){
this.timer = setInterval(function(){
let opacity = this.state.opacity;
opacity -= 0.05;
if(opacity < 0.1){
opacity = 1.0;
}
this.setState({
opacity : opacity
});
}.bind(this), 100);
},
render: function(){
return(
<div key="div" style={{opacity: this.state.opacity}}>
Hi {this.props.name}
</div>
);
}
});
ReactDOM.render(
<Hi name="React" />,
document.getElementById("demo11")
);
</script>
</body>
</html>

上面代码在hello组件加载以后,通过 componentDidMount 方法设置一个定时器,每隔100毫秒,就重新设置组件的透明度,从而引发重新渲染。

另外,组件的style属性的设置方式也值得注意,不能写成


style="opacity:{this.state.opacity};"

而要写成


style={{opacity: this.state.opacity}}

这是因为 React 组件样式是一个对象,所以第一重大括号表示这是 JavaScript 语法,第二重大括号表示样式对象。

十二、参考链接

  1. React's official site
  2. React's official examples
  3. React (Virtual) DOM Terminology, by Sebastian Markbåge
  4. The React Quick Start Guide, by Jack Callister
  5. Learning React.js: Getting Started and Concepts, by Ken Wheeler
  6. Getting started with React, by Ryan Clark
  7. React JS Tutorial and Guide to the Gotchas, by Justin Deal
  8. React Primer, by Binary Muse
  9. jQuery versus React.js thinking, by zigomir

React 入门实例的更多相关文章

  1. React 入门实例教程(转载)

    本人转载自: React 入门实例教程

  2. let import export React入门实例教程 connect provider combineReducers 箭头函数 30分钟掌握ES6/ES2015核心内容 Rest babel

    let与var的区别 http://www.cnblogs.com/snandy/archive/2015/05/10/4485832.html es6 导入导出 http://www.csdn.ne ...

  3. React 入门实例教程

    现在最热门的前端框架,毫无疑问是 React . 上周,基于 React 的 React Native 发布,结果一天之内,就获得了 5000 颗星,受瞩目程度可见一斑. React 起源于 Face ...

  4. 2015年最热门前端框架React 入门实例教程

    现在最热门的前端框架,毫无疑问是 React . 上周,基于 React 的 React Native 发布,结果一天之内,就获得了 5000 颗星,受瞩目程度可见一斑. React 起源于 Face ...

  5. React入门实例教程

    文章转自:阮一峰 现在最热门的前端框架,毫无疑问是 React . 上周,基于 React 的 React Native 发布,结果一天之内,就获得了 5000 颗星,受瞩目程度可见一斑. React ...

  6. React 入门实例教程(转载)

    现在最热门的前端框架,毫无疑问是 React . 上周,基于 React 的 React Native 发布,结果一天之内,就获得了 5000 颗星,受瞩目程度可见一斑. React 起源于 Face ...

  7. 【转】react入门实例教程

    作者: 阮一峰 日期: 2015年3月31日 写在前面:原文链接http://www.ruanyifeng.com/blog/2015/03/react.html    github地址https:/ ...

  8. React 入门实例教程【转】

    Any day will do. 哪一天都行 Are you kidding? 你在开玩笑吧! Congratulations! 祝贺你! I don’t mean it. 我不是故意的. 原文作者: ...

  9. 不会几个框架,都不好意思说搞过前端: React 入门实例教程

    现在最热门的前端框架,毫无疑问是 React . 上周,基于 React 的 React Native 发布,结果一天之内,就获得了 5000 颗星,受瞩目程度可见一斑. React 起源于 Face ...

随机推荐

  1. MUI中等待框的H5实现

    MUI没有内置的那个弹出转圈圈的那个等待框,那个nativeui.showwaiting是只能用于app中的,不能用在H5网页中的,网上找了下,找到个别人已经写好的,自己 测试了下没问题,先记下来 @ ...

  2. FOR XML PATH 可以将查询结果根据行输出成XML格式

    SELECT CAST(OrderID AS varchar)+',' as OrderNo FROM Product CAST函数用于将某种数据类型的表达式显式转换为另一种数据类型 SELECT C ...

  3. 【Tomcat】Tomcat 系统架构与设计模式,第 2 部分: 设计模式分析

    这个分为两个部分的系列文章研究了 Apache Tomcat 服务器的系统架构以及其运用的很多经典设计模式.第 1 部分 分析了 Tomcat 的工作原理,第 2 部分将分析 Tomcat 中运用的许 ...

  4. RNN,LSTM,GRU简单图解:

    一篇经典的讲解RNN的,大部分网络图都来源于此:http://colah.github.io/posts/2015-08-Understanding-LSTMs/ 每一层每一时刻的输入输出:https ...

  5. golang 命令行cobra妙用

    为什么使用命令行 大型项目中少不了数据升级,如果采用web服务,一来不够安全,二来数据量大的时候也会出超时的情况.这时使用命令行是比较合适的方式了. 命令行中的MVC web项目一般采用MVC模式,对 ...

  6. 【emWin】例程二十:窗口对象——Dropdown

    简介: DROPDOWN 小工具用于从具有若干栏的列表中选择一个元素,它以非打开状态显示当前选择的项目.如果用户打开DROPDOWN 小工具,就会出现一个选择新项目的LISTBOX. 触摸校准(上电可 ...

  7. MT7601 WG209模块驱动移植,并连接路由器

    驱动位置: https://github.com/Aplexchenfl/WG209_MT7601 下载之后,查看 Makefile 在这里,我修改了 kernel的位置以及编译器的版本 执行 mak ...

  8. VueThink配置

    vuethink 配置 原文地址:http://blog.csdn.net/hero82748274/article/details/76100938

  9. Android短信监听实现,及Android4.4之后短信机制变更

    前阵子公司有一个项目,简单的监听短信应用,功能只有如下两个: 1.监听短信并获取短信内容上传服务器: 2.从服务器获取短信内容,发送出去    按照传统的思路,监听短信我们有两种方式:第一种是使用广播 ...

  10. ImportError: libmysqlclient_r.so.16: cannot open shared object file: No such file or directory

    在开发一个python项目是,需要用到mysql,但是, 安装完mysql-python后import加载模块提示以下错误: ImportError: libmysqlclient_r.so.16: ...