react.js 学习
react.js是什么⌗
react.js 是一个帮助你构建页面 UI 的库。如果你熟悉 MVC 概念的话,那么 react 的组件就相当于 MVC 里面的 View。如果你不熟悉也没关系,你可以简单地理解为,react.js 将帮助我们将界面分成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,就成了我们的页面。
一个组件的显示形态和行为有可能是由某些数据决定的。而数据是可能发生改变的,这时候组件的显示形态就会发生相应的改变。而 react.js 也提供了一种非常高效的方式帮助我们做到了数据和组件显示形态之间的同步。
react.js 不是一个框架,它只是一个库。它只提供 UI (view)层面的解决方案。在实际的项目当中,它并不能解决我们所有的问题,需要结合其它的库,例如 Redux、react-router 等来协助提供完整的解决方法。
关于Virtual DOM⌗
真实的页面对应一个DOM树,传统的交互就是 DOM树触发事件 -> 然后业务处理 -> 操纵dom树。操作DOM性能消耗大,且繁琐,维护成本高。
于是 React把真实的DOM树转换成Javascript树,也就是Virtual DOM(我觉得可以表述成这样,不直接操作DOM,将DOM抽象成一个javascript对象树【dom元素可以表示成一个JS对象】,操作对象树更加友好)。用户不直接操纵DOM,通过Vitual DOM 去改变DOM。Virtual DOM是通过计算比对前后两个状态(state)的数据对发生变化的部分做批量更新。真实dom数操作的越少,前端性能越优。
安装 react.js⌗
在安装之前要确认你的机器上安装了 node.js 环境包括 npm。如果没有安装的同学可以到 node.js 的官网下载自己电脑的对应的安装包来安装好环境。
安装好环境以后,只需要按照官网的指引安装 create-react-app 即可。
npm install -g create-react-app
这条命令会往我们的机器上安装一条叫 create-react-app 的命令,安装好以后就可以直接使用它来构建一个 react 的前端工程:
create-react-app hello-react
下载完以后我们就可以启动工程了,进入工程目录然后通过 npm 启动工程:
cd hello-react
npm start
运行完命令之后,浏览器会自动打开相应的页面,我们可以通过修改src目录下面的App.js去更新页面上面展示的内容,所有的代码都是实时进行刷新的。
组件(components)⌗
打开src下面的App.js文件,此处的文件我做了修改
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<h1 className='title'>
Learn React
</h1>
</div>
);
}
}
export default App;
我们在文件头部从 react 的包当中引入了 React 和 React.js 的组件父类 Component。记住,只要你要写 React.js 组件,那么就必须要引入这两个东西。
ReactDOM 可以帮助我们把 React 组件渲染到页面上去,没有其它的作用了。你可以发现它是从 react-dom 中引入的,而不是从 react 引入。
代码解释:一个组件继承 Component 类,有一个 render 方法,并且把这个组件的 HTML 结构返回;这里 return 的东西就比较奇怪了,它并不是一个字符串,看起来像是纯 HTML 代码写在 JavaScript 代码里面。你也许会说,这不就有语法错误了么?这完全不是合法的 JavaScript 代码。这种看起来“在 JavaScript 写的标签的”语法叫 JSX。
JSX 原理⌗
如何用 JavaScript 对象来表现一个 DOM 元素的结构,举个例子:
<div class='box' id='content'>
<div class='title'>Hello</div>
<button>Click</button>
</div>
所以其实上面这个 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 的对象结构。
这样的话,上面的App.js代码经过编译
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import './App.css'
class App extends Component {
render () {
return (
React.createElement(
"div",
{ className: 'App' },
React.createElement(
"h1",
{ className: 'title' },
"Learn React"
)
)
)
}
}
export default App;
React.createElement 会构建一个 JavaScript 对象来描述你 HTML 结构的信息,包括标签名、属性、还有子元素等。这样的代码就是合法的 JavaScript 代码了。所以使用 React 和 JSX 的时候一定要经过编译的过程。
这里再重复一遍:所谓的 JSX 其实就是 JavaScript 对象。每当在 JavaScript 代码中看到这种 JSX 结构的时候,脑子里面就可以自动做转化,这样对你理解 React.js 的组件写法很有好处。
记住几个点:
- JSX 是 JavaScript 语言的一种语法扩展,长得像 HTML,但并不是 HTML。
- React.js 可以用 JSX 来描述你的组件长什么样的。
- JSX 在编译的时候会变成相应的 JavaScript 对象描述。
- react-dom 负责把这个用来描述 UI 信息的 JavaScript 对象变成 DOM 元素,并且渲染到页面上。
render()⌗
一个组件类必须要实现一个 render 方法,这个 render 方法必须要返回一个 JSX 元素。但这里要注意的是,必须要用一个外层的 JSX 元素把所有内容包裹起来。返回并列多个 JSX 元素是不合法的,下面是错误的做法:
...
render () {
return (
<div>第一个</div>
<div>第二个</div>
)
}
...
一个简单的示例⌗
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
handleClickOnTitle (e) {
console.log('Click on title.')
console.log(e.target.innerHTML) //e.target.value
}
render() {
const testString = 'test'
const testBoolean = true
const className = 'header'
return (
<div className={className}>
<h1 onClick={this.handleClickOnTitle} style={{color: '#900'}}>{testString}</h1>
{testBoolean
? <strong> TRUE</strong>
: <span> FALSE</span>
}
</div>
);
}
}
export default App;
这个地方包含了jsx变量,事件监控,内联样式等等。。。
state vs props⌗
state⌗
state 的主要作用是用于组件保存、控制、修改自己的可变状态。state 在组件内部初始化,可以被组件自身修改,而外部不能访问也不能修改。你可以认为 state 是一个局部的、只能被组件自身控制的数据源。state 中状态可以通过 this.setState 方法进行更新,setState 会导致组件的重新渲染。
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import './index.css'
class LikeButton extends Component {
constructor () {
super()
this.state = { isLiked: false }
}
handleClickOnLikeButton () {
this.setState({
isLiked: !this.state.isLiked
})
}
render () {
return (
<button onClick={this.handleClickOnLikeButton.bind(this)}>
{this.state.isLiked ? '取消' : '点赞'}
</button>
)
}
}
...
注意:当我们要改变组件的状态的时候,不能直接用 this.state = xxx 这种方式来修改,如果这样做 React.js 就没办法知道你修改了组件的状态,它也就没有办法更新页面。所以,一定要使用 React.js 提供的 setState 方法,它接受一个对象或者函数作为参数。
props⌗
props 的主要作用是让使用该组件的父组件可以传入参数来配置该组件。它是外部传进来的配置参数,组件内部无法控制也无法修改。除非外部组件主动传入新的 props,否则组件的 props 永远保持不变。
class LikeButton extends Component {
constructor () {
super()
this.state = { isLiked: false }
}
handleClickOnLikeButton () {
this.setState({
isLiked: !this.state.isLiked
})
}
render () {
const likedText = this.props.likedText || '取消'
const unlikedText = this.props.unlikedText || '点赞'
return (
<button onClick={this.handleClickOnLikeButton.bind(this)}>
{this.state.isLiked ? likedText : unlikedText} 👍
</button>
)
}
}
在使用一个组件的时候,可以把参数放在标签的属性当中,所有的属性都会作为 props 对象的键值:
class Index extends Component {
render () {
return (
<div>
<LikeButton likedText='已赞' unlikedText='赞' />
</div>
)
}
}
state 和 props 有着千丝万缕的关系。它们都可以决定组件的行为和显示形态。一个组件的 state 中的数据可以通过 props 传给子组件,一个组件可以使用外部传入的 props 来初始化自己的 state。但是它们的职责其实非常明晰分明:state 是让组件控制自己的状态,props 是让外部对组件自己进行配置。
组件生命周期⌗
componentWillMount:组件挂载开始之前,也就是在组件调用 render 方法之前调用。 componentDidMount:组件挂载完成以后,也就是 DOM 元素已经插入页面后调用。 componentWillUnmount:组件对应的 DOM 元素从页面中删除之前调用。