本文记录了自己学习react后对react核心思想的一些理解
背景
React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设Instagram的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。
React 不是一个 MVC 框架,仅仅是视图(V)层的一个用来构建UI的 JavaScript库。React的特点是:
- 使用 JSX语法 创建组件,实现组件化开发,为函数式的 UI 编程方式打开了大门
- 性能高的让人称赞:通过 diff算法 和 虚拟DOM 实现视图的高效更新
React的核心-虚拟DOM
一个HTML页面在被浏览器解析后在内存中实际以DOM树的形式存在。**而React将DOM抽象为虚拟DOM,即用一个JS对象来描述DOM,**然后通过对比前后两个对象的差异,最终只把变化的部分进行重新渲染,提高渲染的效率。React采用虚拟DOM的原因是因为当DOM需要更改时原生DOM可遍历属性太多了,且大部分与渲染无关,因此更新页面代价很大。
VituralDOM的处理方式:
- 用 JavaScript 对象结构表示 DOM 树的结构,然后用这个树构建一个真正的 DOM 树,插到文档当中
- 当前组件状态变更的时候,根据新的状态重新构造一棵新的虚拟DOM树。然后用新的虚拟DOM树和旧的虚拟DOM树进行比较,记录两棵树差异
- 把2所记录的差异通过JS中setChild等操作DOM树的方式应用到步骤1所构建的真正的DOM树上,这时视图就更新了
React核心-Diff算法
当我们使用React的时候,在某个时间点 render() 函数创建了一棵React元素树, 在下一个state或者props更新的时候,render() 函数将创建一棵新的React元素树, React将对比这两棵树的不同之处,计算出如何高效的更新UI**(即它只会更新变化的地方)**
重点:
- React不同于直接通过div.style.top = '10px’这样的方式修改界面,这样直接操作如果操作了4个style就会让页面刷新4次,效率很低,而react通过虚拟DOM和Diff算法一次收集了某个组件所有的修改项,然后一次性写入DOM树中,从而实现页面的一次刷新。
- React修改真实的DOM数是通过操作DOM数节点的方式修改的,这种方式如果没有涉及到页面的布局变化是不会导致页面整体重新加载刷新的,不想innerHTML这样,所以效率很高。
React基本使用
- 安装:npm i -S react react-dom
- react:react 是React库的入口点
- react-dom:提供了针对DOM的方法,比如:把创建的虚拟DOM,渲染到页面上
// 1. 导入 react
import React from 'react'
import ReactDOM from 'react-dom'
// 2. 创建 虚拟DOM
// 参数1:元素名称 参数2:元素属性对象(null表示无) 参数3:当前元素的子元素string||createElement() 的返回值
const divVD = React.createElement('div', {
title: 'hello react'
}, 'Hello React!!!')
// 3. 渲染
// 参数1:虚拟dom对象 参数2:dom对象表示渲染到哪个元素内 参数3:回调函数
ReactDOM.render(divVD, document.getElementById('app'))
React可以通过createElement()的方式来创建虚拟DOM,但是这种方式用户等于是直接在通过DOM树的结构来编写界面,代码编写不友好,太过复杂。因此React推荐使用JSX语法来实现UI编程方式。
React核心-jsx语法
- 注意:JSX语法,最终会被编译为 createElement() 方法
- 推荐:使用 JSX 的方式创建组件
- JSX - JavaScript XML
- 安装:npm i -D babel-preset-react (依赖与:babel-core/babel-loader)
注意:JSX的语法需要通过 babel-preset-react 编译后,才能被解析执行,其实JSX语法被解析后就是通过createElement方法来实现的,如下所示:
// 1、JSX
const element = (
<h1 className="greeting">
Hello, world!
</h1>
)
// 2、JSX -> createElement
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
)
// React elements: 使用对象的形式描述页面结构
// Note: 这是简化后的对象结构
const element = {
type: 'h1',
props: {
className: 'greeting',
},
children: ['Hello, world']
}
React创建组件的两种方式
React 组件可以让你把UI分割为独立、可复用的片段,并将每一片段视为相互独立的部分。
- 组件是由一个个的HTML元素组成的
- 概念上来讲, 组件就像JS中的函数。它们接受用户输入(props),并且返回一个React对象,用来描述展示在页面中的内容
React创建组件分为两种方式:
- 通过 JS函数 创建(无状态组件)
- 通过 class 创建(有状态组件)
函数式组件 和 class 组件的使用场景说明:
- 如果一个组件仅仅是为了展示数据,那么此时就可以使用 函数组件**(因为其实就是被调用的时候返回一个虚拟DOM对象而已)**
- 如果一个组件中有一定业务逻辑,需要操作数据,那么就需要使用 class 创建组件,因为,此时需要使用 state
如下:
//*********函数式组件
function Welcome(props){
// props ---> { username: 'zs', age: 20 }
return (
<div>
<div>Welcome React</div>
<h3>姓名:{props.username}----年龄是:{props.age}</h3>
</div>
)
}
// 给 Hello组件 传递 props:username 和 age(如果你想要传递numb类型是数据 就需要向下面这样)
ReactDOM.reander(<Hello username="zs" age={20}></Hello>, ......)
//************类组件
// react对象继承字React.Component
class Hello extends React.Component {
constructor() {
// es6继承必须用super调用父类的constructor
super()
this.state = {
gender: 'male'
}
}
render() {
return (
<div>性别:{ this.state.gender }</div>
)
}
}
props和state
props:
- 作用:给组件传递数据,一般用在父子组件之间
说明:React把传递给组件的属性转化为一个对象并交给 props
- 特点:props是只读的,无法给props添加或修改属性
- props.children:获取组件的内容,比如:
- 组件内容 中的 组件内容
state:状态即数据
- 作用:用来给组件提供组件内部使用的数据
- 注意:只有通过class创建的组件才具有状态
- 状态是私有的,完全由组件来控制
- 不要在 state 中添加 render() 方法中不需要的数据,会影响渲染性能!
- 可以将组件内部使用但是不渲染在视图中的内容,直接添加给 this
- 不要在 render() 方法中调用 setState() 方法来修改state的值
在调用setState时React会调用Render去刷新界面,从而实现元素与数据间的双向同步。