React 入门实例教程
来源:互联网 发布:里海大学本科 知乎 编辑:程序博客网 时间:2024/06/06 08:45
作者:
日期:
现在最热门的前端框架,毫无疑问是
上周,基于 React 的
React 起源于 Facebook 的内部项目,因为该公司对市场上所有
由于 React 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。所以,越来越多的人开始关注和使用,认为它可能是将来 Web 开发的主流工具。
这个项目本身也越滚越大,从最早的UI引擎变成了一整套前后端通吃的 Web App 解决方案。衍生的 React Native 项目,目标更是宏伟,希望用写 Web App 的方式去写 Native App。如果能够实现,整个互联网行业都会被颠覆,因为同一组人只需要写一次 UI ,就能同时运行在服务器、浏览器和手机(参见《也许,DOM 不是答案》)。
既然 React 这么热门,看上去充满希望,当然应该好好学一下。从技术角度,可以满足好奇心,提高技术水平;从职业角度,有利于求职和晋升,有利于参与潜力大的项目。但是,好的 React 教程却不容易找到,这一方面因为这项技术太新,刚刚开始走红,大家都没有经验,还在摸索之中;另一方面因为 React 本身还在不断变动,API 一直在调整,至今没发布1.0版。
我学习 React 时,就很苦恼。有的教程讨论一些细节问题,对入门没帮助;有的教程写得不错,但比较短,无助于看清全貌。我断断续续学了几个月,看过二十几篇教程,在这个过程中,将对自己有帮助的 Demo 都收集下来,做成了一个库
下面,我就根据这个库,写一篇全面又易懂的 React 入门教程。你只需要跟着每一个 Demo 做一遍,就能初步掌握 React 。当然,前提是你必须拥有基本 JavaScript 和 DOM 知识,但是你读完就会发现,React 所要求的预备知识真的很少。
零、安装
React 的安装包,可以到官网下载。不过,React Demos
$ git clone git@github.com:ruanyf/react-demos.git
如果你没安装 git, 那就直接下载
下面要讲解的12个例子在各个 Demo
index.html
需要说明的是,React 可以在浏览器运行,也可以在服务器运行,但是本教程只涉及浏览器。一方面是为了尽量保持简单,另一方面 React 的语法是一致的,服务器的用法与浏览器差别不大。Demo13
一、HTML 模板
使用 React 的网页源码,结构大致如下。
<</span>!DOCTYPE html><</span>html> <</span>head> <</span>script src="../build/react.js"><</span>/script> <</span>script src="../build/react-dom.js"><</span>/script> <</span>script src="../build/browser.min.js"><</span>/script> <</span>/head> <</span>body> <</span>div id="example"><</span>/div> <</span>script type="text/babel"> // ** Our code goes here! ** <</span>/script> <</span>/body><</span>/html>
上面代码有两个地方需要注意。首先,最后一个 type
text/babel
type="text/babel"
其次,上面代码一共用了三个库: react.js
react-dom.js
Browser.js
react.js
react-dom.js
Browser.js
$ babel src --out-dir build
上面命令可以将 src
js
build
二、ReactDOM.render()
ReactDOM.render 是 React 的最基本方法,用于将模板转为 HTML 语言,并插入指定的 DOM 节点。
ReactDOM.render( <</span>h1>Hello, world!<</span>/h1>, document.getElementById('example'));
上面代码将一个 h1
example
demo01
),运行结果如下。
三、JSX 语法
上一节的代码, HTML 语言直接写在 JavaScript 语言之中,不加任何引号,这就是 Demo02
var names = ['Alice', 'Emily', 'Kate'];ReactDOM.render( <</span>div> { names.map(function (name) { return <</span>div>Hello, {name}!<</span>/div> }) } <</span>/div>, document.getElementById('example'));
上面代码体现了 JSX 的基本语法规则:遇到 HTML 标签(以 <</code>
{
JSX 允许直接在模板插入 JavaScript 变量。如果这个变量是一个数组,则会展开这个数组的所有成员(查看 demo03
var arr = [ <</span>h1>Hello world!<</span>/h1>, <</span>h2>React is awesome<</span>/h2>,];ReactDOM.render( <</span>div>{arr}<</span>/div>, document.getElementById('example'));
上面代码的arr
变量是一个数组,结果 JSX 会把它的所有成员,添加到模板,运行结果如下。
四、组件
React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件。React.createClass 方法就用于生成一个组件类(查看 demo04
)。
var HelloMessage = React.createClass({ render: function() { return <</span>h1>Hello {this.props.name}<</span>/h1>; }});ReactDOM.render( <</span>HelloMessage name="John" />, document.getElementById('example'));
上面代码中,变量 HelloMessage
HelloMessage
render
注意,组件类的第一个字母必须大写,否则会报错,比如HelloMessage
不能写成helloMessage
。另外,组件类只能包含一个顶层标签,否则也会报错。
var HelloMessage = React.createClass({ render: function() { return <</span>h1> Hello {this.props.name} <</span>/h1><</span>p> some text <</span>/p>; }});
上面代码会报错,因为HelloMessage
组件包含了两个顶层标签:h1
和p
。
组件的用法与原生的 HTML 标签完全一致,可以任意加入属性,比如 HelloMessage
name
John
。组件的属性可以在组件类的 this.props
name
this.props.name
添加组件属性,有一个地方需要注意,就是 class
className
for
htmlFor
class
for
五、this.props.children
this.props
this.props.children
demo05
)。
var NotesList = React.createClass({ render: function() { return ( <</span>ol> { React.Children.map(this.props.children, function (child) { return <</span>li>{child}<</span>/li>; }) } <</span>/ol> ); }});ReactDOM.render( <</span>NotesList> <</span>span>hello<</span>/span> <</span>span>world<</span>/span> <</span>/NotesList>, document.body);
上面代码的 NoteList
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
属性,就是用来验证组件实例的属性是否符合要求(查看 demo06
)。
var MyTitle = React.createClass({ propTypes: { title: React.PropTypes.string.isRequired, }, render: function() { return <</span>h1> {this.props.title} <</span>/h1>; }});
上面的Mytitle
组件有一个title
属性。PropTypes
title
title
var data = 123;ReactDOM.render( <</span>MyTitle title={data} />, document.body);
这样一来,title
属性就通不过验证了。控制台会显示一行错误信息。
Warning: Failed propType: Invalid prop `title` of type `number` supplied to `MyTitle`, expected `string`.
更多的PropTypes
设置,可以查看官方文档。
此外,getDefaultProps
var MyTitle = React.createClass({ getDefaultProps : function () { return { title : 'Hello World' }; }, render: function() { return <</span>h1> {this.props.title} <</span>/h1>; }});ReactDOM.render( <</span>MyTitle />, document.body);
上面代码会输出"Hello World"。
七、获取真实的DOM节点
组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM)。只有当它插入文档以后,才会变成真实的 DOM 。根据 React 的设计,所有的 DOM 变动,都先在虚拟 DOM 上发生,然后再将实际发生变动的部分,反映在真实 DOM上,这种算法叫做
但是,有时需要从组件获取真实 DOM 的节点,这时就要用到 ref
var MyComponent = React.createClass({ handleClick: function() { this.refs.myTextInput.focus(); }, render: function() { return ( <</span>div> <</span>input type="text" ref="myTextInput" /> <</span>input type="button" value="Focus the text input" onClick={this.handleClick} /> <</span>/div> ); }});ReactDOM.render( <</span>MyComponent />, document.getElementById('example'));
上面代码中,组件 MyComponent
ref
this.refs.[refName]
需要注意的是,由于 this.refs.[refName]
Click
Click
this.refs.[refName]
React 组件支持很多事件,除了 Click
KeyDown
Copy
、Scroll
八、this.state
组件免不了要与用户互动,React 的一大创新,就是将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染 UI (查看 demo08
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 ( <</span>p onClick={this.handleClick}> You {text} this. Click to toggle. <</span>/p> ); }});ReactDOM.render( <</span>LikeButton />, document.getElementById('example'));
上面代码是一个 LikeButton
getInitialState
this.state
this.setState
this.render
由于 this.props
this.state
this.props
this.state
九、表单
用户在表单填入的内容,属于用户跟组件的互动,所以不能用 this.props
demo9
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 ( <</span>div> <</span>input type="text" value={value} onChange={this.handleChange} /> <</span>p>{value}<</span>/p> <</span>/div> ); }});ReactDOM.render(<</span>Input/>, document.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 还提供两种特殊状态的处理函数。
- componentWillReceiveProp
s(object nextProps):已加载组件收到新的参数时调用 - shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用
这些方法的详细说明,可以参考官方文档。下面是一个例子(查看 demo10
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 <</span> 0.1) { opacity = 1.0; } this.setState({ opacity: opacity }); }.bind(this), 100); }, render: function () { return ( <</span>div style={{opacity: this.state.opacity}}> Hello {this.props.name} <</span>/div> ); }});ReactDOM.render( <</span>Hello name="world"/>, document.body);
上面代码在hello
组件加载以后,通过 componentDidMount
另外,组件的style
属性的设置方式也值得注意,不能写成
style="opacity:{this.state.opacity};"
而要写成
style={{opacity: this.state.opacity}}
这是因为
十一、Ajax
组件的数据来源,通常是通过 Ajax 请求从服务器获取,可以使用 componentDidMount
this.setState
demo11
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 ( <</span>div> {this.state.username}'s last gist is <</span>a href={this.state.lastGistUrl}>here<</span>/a>. <</span>/div> ); }});ReactDOM.render( <</span>UserGist source="https://api.github.com/users/octocat/gists" />, document.body);
上面代码使用 jQuery 完成 Ajax 请求,这是为了便于说明。React 本身没有任何依赖,完全可以不用jQuery,而使用其他库。
我们甚至可以把一个Promise对象传入组件,请看Demo12
。
ReactDOM.render( <</span>RepoList promise={$.getJSON('https://api.github.com/search/repositories?q=javascript&sort=stars')} />, document.body);
上面代码从Github的API抓取数据,然后将Promise对象作为属性,传给RepoList
组件。
如果Promise对象正在抓取数据(pending状态),组件显示"正在加载";如果Promise对象报错(rejected状态),组件显示报错信息;如果Promise对象抓取数据成功(fulfilled状态),组件显示获取的数据。
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>span>Loading...<</span>/span>; } else if (this.state.error !== null) { return <</span>span>Error: {this.state.error.message}<</span>/span>; } else { var repos = this.state.data.items; var repoList = repos.map(function (repo) { return ( <</span>li> <</span>a href={repo.html_url}>{repo.name}<</span>/a> ({repo.stargazers_count} stars) <</span>br/> {repo.description} <</span>/li> ); }); return ( <</span>main> <</span>h1>Most Popular JavaScript Projects in Github<</span>/h1> <</span>ol>{repoList}<</span>/ol> <</span>/main> ); } }});
- React 入门实例教程
- 干货!React入门实例教程
- React入门实例教程 | 干货
- React 入门实例教程
- React 入门实例教程总结
- React 入门实例教程
- React 入门实例教程
- React 入门实例教程
- React 入门实例教程
- React 入门实例教程
- React 入门实例教程
- React 入门实例教程
- React 入门实例教程
- React 入门实例教程
- React 入门实例教程
- React 入门实例教程
- [转]React 入门实例教程
- React 入门实例教程
- java中如何把hashmap转换成object数组
- Android的各种零碎知识点(持续补充)
- maven之继承、聚合、依赖
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- CocoaPods安装和使用
- React 入门实例教程
- javascript 返回页面
- List与Array转换
- c#交叉数组,多维数组
- `这个符号在mysql中的作用
- 关于equals与"=="的区别
- Yii CGridView CButtonColumn, ajax 自定义按钮之三
- BLE 广播报文解析
- iOS巅峰之开发过程中的小知识点大全