React入门(一)

React入门(一)
转载自:http://huziketang.mangojuice.top/books/react/
文章目录
- React入门(一)
- 前提知识
- ES6
- 箭头函数
- 安装
- JSX
- 原理
- JSX 元素变量
- render方法和组合
- 方法
- 表达式插入
- 组件组合
- 事件监听
- event 对象
- 关于事件中的 this
前提知识
ES6
ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了。它的目标,是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
现在的大多数的浏览器能支持ES6,并且我们能通过babel语法转化器,将ES6转化为能被大多数浏览器能够支持的ES5。
对 ES6 的支持可以查看kangax.github.io/compat-table/ES6/。随着时间的推移,支持度已经越来越高了,超过 90%的 ES6 语法特性都实现了。
流行的库基本都基于es6构建,React默认使用es6新语法开发。
箭头函数
ES6 允许使用“箭头”(=>)定义函数。
var f = v => v;//将参数和返回值提取出来// 等同于
var f = function (v) {
return v;
};
如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。
var f = () => 5;// 等同于
var f = function () { return 5 };
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。
更多用法:箭头函数
安装
React.js 单独使用基本上是不可能的事情。不要指望着类似于 jQuery 下载放到 <head /> 标签就开始使用。使用 React.js 不管在开发阶段生产阶段都需要一堆工具和库辅助,编译阶段你需要借助 Babel;需要 Redux 等第三方的状态管理工具来组织代码;如果你要写单页面应用那么你需要 React-router。这就是所谓的React.js全家桶。
工具地址:https://github.com/facebookincubator/create-react-app
在安装之前要确认你的机器上安装了node.js环境包括 npm。
如果没有安装的同学可以到 node.js的官网下载自己电脑的对应的安装包来安装好环境。
安装好环境以后,只需要按照官网的指引安装 create-react-app 即可。
npm install -g create-react-app这条命令会往我们的机器上安装一条叫 create-react-app 的命令,安装好以后就可以直接使用它来构建一个 react 的前端工程:
选择项目地址(这我选择桌面)
cd Desktop构建一个名叫hello-react的工程
create-react-app hello-react并且会自动地帮助我们安装所需要的依赖,现在只需要安静地等待它安装完。
额外的小贴士:
如果有些同学安装过程比较慢,那是很有可能是因为 npm 下载的时候是从国外的源下载的缘故。所以可以把 npm 的源改成国内的 taobao 的源,这样会加速下载过程。在执行上面的命令之前可以先修改一下 npm 的源:
npm config set registry https://registry.npm.taobao.org
下载完以后我们就可以启动工程了,进入工程目录然后通过 npm 启动工程:
cd hello-react//进入项目内npm start
终端提示成功:
JSX
原理
为了让大家深刻理解 JSX 的含义。有必要简单介绍了一下 JSX 稍微底层的运作原理,这样大家可以更加深刻理解 JSX 到底是什么东西,为什么要有这种语法,它是经过怎么样的转化变成页面的元素的。
思考一个问题:如何用 JavaScript 对象来表现一个 DOM 元素的结构,举个例子:
<div class='box' id='content'> <div class='title'>Hello</div>
<button>Click</button>
</div>
每个 DOM 元素的结构都可以用 JavaScript 的对象来表示。你会发现一个 DOM 元素包含的信息其实只有三个:标签名,属性,子元素。
所以其实上面这个 HTML 所有的信息我们都可以用合法的 JavaScript 对象来表示:
{ tag: 'div',
attrs: { className: 'box', id: 'content'},
children: [
{
tag: 'div',
arrts: { className: 'title' },
children: ['Hello']
},
{
tag: 'button',
attrs: null,
children: ['Click']
}
]
}
你会发现,HTML 的信息和 JavaScript 所包含的结构和信息其实是一样的,我们可以用 JavaScript 对象来描述所有能用 HTML 表示的 UI 信息。但是用 JavaScript 写起来太长了,结构看起来又不清晰,用 HTML 的方式写起来就方便很多了。
于是 React.js 就把 JavaScript 的语法扩展了一下,让 JavaScript 语言能够支持这种直接在 JavaScript 代码里面编写类似 HTML 标签结构的语法,这样写起来就方便很多了。编译的过程会把类似 HTML 的 JSX 结构转换成 JavaScript 的对象结构。
上面的代码:
import React, { Component } from 'react'import ReactDOM from 'react-dom'
import './index.css'
class Header extends Component {
render () {
return (
<div>
<h1 className='title'>React 小书</h1>
</div>
)
}
}
ReactDOM.render(
<Header />,
document.getElementById('root')
)
经过编译以后会变成:
import React, { Component } from 'react'import ReactDOM from 'react-dom'
import './index.css'
class Header extends Component {
render () {
return (
React.createElement(
"div",
null,
React.createElement(
"h1",
{ className: 'title' },
"React 小书"
)
)
)
}
}
ReactDOM.render(
React.createElement(Header, null),
document.getElementById('root')
);
React.createElement 会构建一个 JavaScript 对象来描述你 HTML 结构的信息,包括标签名、属性、还有子元素等。这样的代码就是合法的 JavaScript 代码了。所以使用 React 和 JSX 的时候一定要经过编译的过程。
这里再重复一遍:所谓的 JSX 其实就是 JavaScript 对象。每当在 JavaScript 代码中看到这种 JSX 结构的时候,脑子里面就可以自动做转化,这样对你理解 React.js 的组件写法很有好处。
有了这个表示 HTML 结构和信息的对象以后,就可以拿去构造真正的 DOM 元素,然后把这个 DOM 元素塞到页面上。这也是我们最后一段代码中 ReactDOM.render 所干的事情:
ReactDOM.render( <Header />,
document.getElementById('root')
)
ReactDOM.render 功能就是把组件渲染并且构造 DOM 树,然后插入到页面上某个特定的元素上(在这里是 id 为 root 的 div 元素)。
JSX 元素变量
同样的,如果你能理解 JSX 元素就是 JavaScript 对象。那么你就可以联想到,JSX 元素其实可以像 JavaScript 对象那样自由地赋值给变量,或者作为函数参数传递、或者作为函数的返回值。
...render () {
const isGoodWord = true
const goodWord = <span> is good</span>
const badWord = <span> is not good</span>
return (
<div>
<h1>
React 小书
{isGoodWord ? goodWord : badWord}
</h1>
</div>
)
}
...
这里给把两个 JSX 元素赋值给了 goodWord 和 badWord 两个变量,然后把它们作为表达式插入的条件返回值。
再举一个例子:
...renderGoodWord (goodWord, badWord) {
const isGoodWord = true
return isGoodWord ? goodWord : badWord
}
render () {
return (
<div>
<h1>
React 小书
{this.renderGoodWord(
<span> is good</span>,
<span> is not good</span>
)}
</h1>
</div>
)
}
...
这里我们定义了一个 renderGoodWord 函数,这个函数接受两个 JSX 元素作为参数,并且随机返回其中一个。在 render 方法中,我们把上面例子的两个 JSX 元素传入 renderGoodWord 当中,通过表达式插入把该函数返回的 JSX 元素插入到页面上。
render方法和组合
方法
React.js 中一切皆组件,用 React.js 写的其实就是 React.js 组件。我们在编写 React.js 组件的时候,一般都需要继承 React.js 的 Component(还有别的编写组件的方式我们后续会提到)。一个组件类必须要实现一个 render 方法
这个 render 方法必须要返回一个 JSX 元素。但这里要注意的是,必须要用一个外层的 JSX 元素把所有内容包裹起来。返回并列多个 JSX 元素是不合法的,下面是错误的做法:
...render () {
return (
<div>第一个</div>
<div>第二个</div>
)
}
...
必须要用一个外层元素把内容进行包裹:
...render () {
return (
<div>
<div>第一个</div>
<div>第二个</div>
</div>
)
}
...
表达式插入
在 JSX 当中你可以插入 JavaScript 的表达式,表达式返回的结果会相应地渲染到页面上。表达式用 {} 包裹。例如:
...render () {
const word = 'is good'
return (
<div>
<h1>React 小书 {word}</h1>
</div>
)
}
...
页面上就显示“React 小书 is good”。你也可以把它改成 {1 + 2},它就会显示 “React 小书 3”。你也可以把它写成一个函数表达式返回:
...render () {
return (
<div>
<h1>React 小书 {(function () { return 'is good'})()}</h1>
</div>
)
}
...
简而言之,{} 内可以放任何 JavaScript 的代码,包括变量、表达式计算、函数执行等等。 render 会把这些代码返回的内容如实地渲染到页面上,非常的灵活。
表达式插入不仅仅可以用在标签内部,也可以用在标签的属性上,例如:
...render () {
const className = 'header'
return (
<div className={className}>
<h1>React 小书</h1>
</div>
)
}
...
这样就可以为 div 标签添加一个叫 header 的类名。
注意,直接使用 class 在 React.js 的元素上添加类名如 <div class=“xxx”> 这种方式是不合法的。因为 class 是 JavaScript 的关键字,所以 React.js 中定义了一种新的方式:className 来帮助我们给元素添加类名。
还有一个特例就是 for 属性,例如 <label for='male'>Male</label>,因为 for 也是 JavaScript 的关键字,所以在 JSX 用 htmlFor 替代,即 <label htmlFor='male'>Male</label>。而其他的 HTML 属性例如 style 、data-* 等就可以像普通的 HTML 属性那样直接添加上去。
组件组合
假设我们现在构建一个新的组件叫 Title,它专门负责显示标题。你可以在 Header 里面使用 Title组件:
class Title extends Component { render () {
return (
<h1>React 小书</h1>
)
}
}
class Header extends Component {
render () {
return (
<div>
<Title />
</div>
)
}
}
我们可以直接在 Header 标签里面直接使用 Title 标签。就像是一个普通的标签一样。React.js 会在 <Title /> 所在的地方把 Title 组件的 render 方法表示的 JSX 内容渲染出来,也就是说 <h1>React 小书</h1> 会显示在相应的位置上。
组件组合
事件监听
在 React.js 里面监听事件是很容易的事情,你只需要给需要监听事件的元素加上属性类似于 onClick、onKeyDown 这样的属性,例如我们现在要给 Title 加上点击的事件监听:
class Title extends Component { handleClickOnTitle () {
console.log('Click on title.')
}
render () {
return (
<h1 onClick={this.handleClickOnTitle}>React 小书</h1>
)
}
}
只需要给 h1 标签加上 onClick 的事件,onClick 紧跟着是一个表达式插入,这个表达式返回一个 Title 自己的一个实例方法。当用户点击 h1 的时候,React.js 就会调用这个方法,所以你在控制台就可以看到 Click on title. 打印出来。
在 React.js 不需要手动调用浏览器原生的 addEventListener 进行事件监听。React.js 帮我们封装好了一系列的 on* 的属性,当你需要为某个元素监听某个事件的时候,只需要简单地给它加上 on*就可以了。而且你不需要考虑不同浏览器兼容性的问题,React.js 都帮我们封装好这些细节了。
React.js 封装了不同类型的事件,这里就不一一列举,有兴趣的同学可以参考官网文档: SyntheticEvent - React,多尝试不同的事件。另外要注意的是,这些事件属性名都必须要用驼峰命名法。
没有经过特殊处理的话,这些 on* 的事件监听只能用在普通的 HTML 的标签上,而不能用在组件标签上。也就是说,<Header onClick={…} /> 这样的写法不会有什么效果的。这一点要注意,但是有办法可以做到这样的绑定,以后我们会提及。现在只要记住一点就可以了:这些 on* 的事件监听只能用在普通的 HTML 的标签上,而不能用在组件标签上。
event 对象
和普通浏览器一样,事件监听函数会被自动传入一个 event 对象,这个对象和普通的浏览器 event 对象所包含的方法和属性都基本一致。不同的是 React.js 中的 event 对象并不是浏览器提供的,而是它自己内部所构建的。React.js 将浏览器原生的 event 对象封装了一下,对外提供统一的 API 和属性,这样你就不用考虑不同浏览器的兼容性问题。这个 event 对象是符合 W3C 标准( W3C UI Events )的,它具有类似于event.stopPropagation、event.preventDefault 这种常用的方法。
我们来尝试一下,这次尝试当用户点击 h1 的时候,把 h1 的 innerHTML 打印出来:
class Title extends Component { handleClickOnTitle (e) {
console.log(e.target.innerHTML)
}
render () {
return (
<h1 onClick={this.handleClickOnTitle}>React 小书</h1>
)
}
}
再看看控制台,每次点击的时候就会打印”React 小书“。
关于事件中的 this
一般在某个类的实例方法里面的 this 指的是这个实例本身。但是你在上面的 handleClickOnTitle 中把 this 打印出来,你会看到 this 是 null 或者 undefined。
... handleClickOnTitle (e) {
console.log(this) // => null or undefined
}
...
这是因为 React.js 调用你所传给它的方法的时候,并不是通过对象方法的方式调用(this.handleClickOnTitle),而是直接通过函数调用 (handleClickOnTitle),所以事件监听函数内并不能通过 this获取到实例。
如果你想在事件函数当中使用当前的实例,你需要手动地将实例方法 bind 到当前实例上再传入给 React.js。
class Title extends Component { handleClickOnTitle (e) {
console.log(this)
}
render () {
return (
<h1 onClick={this.handleClickOnTitle.bind(this)}>React 小书</h1>
)
}
}
bind 会把实例方法绑定到当前实例上,然后我们再把绑定后的函数传给 React.js 的 onClick 事件监听。这时候你再看看,点击 h1的时候,就会把当前的实例打印出来:
你也可以在 bind 的时候给事件监听函数传入一些参数:
class Title extends Component { handleClickOnTitle (word, e) {
console.log(this, word)
}
render () {
return (
<h1 onClick={this.handleClickOnTitle.bind(this, 'Hello')}>React 小书</h1>
)
}
}
这种 bind 模式在 React.js 的事件监听当中非常常见,bind 不仅可以帮我们把事件监听方法中的 this 绑定到当前组件实例上;还可以帮助我们在在渲染列表元素的时候,把列表元素传入事件监听函数当中——这个将在以后的章节提及。
如果有些同学对 JavaScript 的 this 模式或者 bind 函数的使用方式不是特别了解到话,可能会对这部分内容会有些迷惑,可以补充对 JavaScript 的 this 和 bind 相关的知识再来回顾这部分内容。
以上是 React入门(一) 的全部内容, 来源链接: utcz.com/z/382737.html

