2021react复习

《千锋HTML5好程序员第三阶段React》学习材料——古艺散人
(自己加了一点笔记更改,算作转载吧

一、create-react-app

全局安装create-react-app

$ npm install -g create-react-app

创建一个项目

$ create-react-app your-app 注意命名方式

Creating a new React app in /dir/your-app.

Installing packages. This might take a couple of minutes. 安装过程较慢,
Installing react, react-dom, and react-scripts... 

如果不想全局安装,可以直接使用npx

$ npx create-react-app your-app	也可以实现相同的效果

这需要等待一段时间,这个过程实际上会安装三个东西

  • react: react的顶级库
  • react-dom: 因为react有很多的运行环境,比如app端的react-native, 我们要在web上运行就使用react-dom
  • react-scripts: 包含运行和打包react应用程序的所有脚本及配置

出现下面的界面,表示创建项目成功:

Success! Created your-app at /dir/your-app
Inside that directory, you can run several commands:

  npm start
    Starts the development server.

  npm run build
    Bundles the app into static files for production.

  npm test
    Starts the test runner.

  npm run eject
    Removes this tool and copies build dependencies, configuration files
    and scripts into the app directory. If you do this, you can’t go back!

We suggest that you begin by typing:

  cd your-app
  npm start

Happy hacking!

根据上面的提示,通过cd your-app命令进入目录并运行npm start即可运行项目。

生成项目的目录结构如下:

├── README.md							使用方法的文档
├── node_modules					所有的依赖安装的目录
├── package-lock.json			锁定安装时的包的版本号,保证团队的依赖能保证一致。
├── package.json					
├── public								静态公共目录
└── src										开发用的源代码目录

常见问题:

  • npm安装失败
    • 切换为npm镜像为淘宝镜像
    • 使用yarn,如果本来使用yarn还要失败,还得把yarn的源切换到国内
    • 如果还没有办法解决,请删除node_modules及package-lock.json然后重新执行npm install命令
    • 再不能解决就删除node_modules及package-lock.json的同时清除npm缓存npm cache clean --force之后再执行npm install命令

二、关于React

1、React的起源和发展

React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。

2、React与传统MVC的关系

轻量级的视图层A JavaScript library for building user interfaces

React不是一个完整的MVC框架,最多可以认为是MVC中的V(View),甚至React并不非常认可MVC开发模式;React 构建页面 UI 的库。可以简单地理解为,React 将界面分成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,就成了我们的页面。

3、React高性能的体现:虚拟DOM

React高性能的原理:

在Web开发中我们总需要将变化的数据实时反应到UI上,这时就需要对DOM进行操作。而复杂或频繁的DOM操作通常是性能瓶颈产生的原因(如何进行高性能的复杂DOM操作通常是衡量一个前端开发人员技能的重要指标)。

React为此引入了虚拟DOM(Virtual DOM)的机制:在浏览器端用Javascript实现了一套DOM API。基于React进行开发时所有的DOM构造都是通过虚拟DOM进行,每当数据变化时,React都会重新构建整个DOM树,然后React将当前整个DOM树和上一次的DOM树进行对比,得到DOM结构的区别,然后仅仅将需要变化的部分进行实际的浏览器DOM更新。而且React能够批处理虚拟DOM的刷新,在一个事件循环(Event Loop)内的两次数据变化会被合并,例如你连续的先将节点内容从A-B, B-A,React会认为A变成B,然后又从B变成A UI不发生任何变化,而如果通过手动控制,这种逻辑通常是极其复杂的。

尽管每一次都需要构造完整的虚拟DOM树,但是因为虚拟DOM是内存数据,性能是极高的,而对实际DOM进行操作的仅仅是Diff分,因而能达到提高性能的目的。这样,在保证性能的同时,开发者将不再需要关注某个数据的变化如何更新到一个或多个具体的DOM元素,而只需要关心在任意一个数据状态下,整个界面是如何Render的。

React Fiber:

在react 16之后发布的一种react 核心算法,React Fiber是对核心算法的一次重新实现(官网说法)。之前用的是diff算法。

在之前React中,更新过程是同步的,这可能会导致性能问题。

当React决定要加载或者更新组件树时,会做很多事,比如调用各个组件的生命周期函数,计算和比对Virtual DOM,最后更新DOM树,这整个过程是同步进行的,也就是说只要一个加载或者更新过程开始,中途不会中断。因为JavaScript单线程的特点,如果组件树很大的时候,每个同步任务耗时太长,就会出现卡顿。

React Fiber的方法其实很简单——分片。把一个耗时长的任务分成很多小片,每一个小片的运行时间很短,虽然总时间依然很长,但是在每个小片执行完之后,都给其他任务一个执行的机会,这样唯一的线程就不会被独占,其他任务依然有运行的机会。

4、React的特点和优势

(1) 虚拟DOM

我们以前操作dom的方式是通过document.getElementById()的方式,这样的过程实际上是先去读取html的dom结构,将结构转换成变量,再进行操作。而reactjs定义了一套变量形式的dom模型,一切操作和换算直接在变量中,这样减少了操作真实dom,性能真实相当的高,和主流MVC框架有本质的区别,并不和dom打交道

(2) 组件系统

react最核心的思想是将页面中任何一个区域或者元素都可以看做一个组件 component

那么什么是组件呢?

组件指的就是同时包含了html、css、js、image元素的聚合体

使用react开发的核心就是将页面拆分成若干个组件,并且react一个组件中同时耦合了css、js、image,这种模式整个颠覆了过去的传统的方式

(3) 单向数据流

其实reactjs的核心内容就是数据绑定,所谓数据绑定指的是只要将一些服务端的数据和前端页面绑定好,开发者只关注实现业务就行了

(4) JSX 语法

在vue中,我们使用render函数来构建组件的dom结构性能较高,因为省去了查找和编译模板的过程,但是在render中利用createElement创建结构的时候代码可读性较低,较为复杂,此时可以利用jsx语法来在render中创建dom,解决这个问题,但是前提是需要使用工具来编译jsx

三、编写第一个react应用程序

react开发需要引入多个依赖文件:react.js、react-dom.js,分别又有开发版本和生产版本,create-react-app里已经帮我们把这些东西都安装好了。把通过CRA创建的工程目录下的src目录清空,然后在里面重新创建一个index.js. 写入以下代码:

// 从 react 的包当中引入了 React。只要你要写 React.js 组件就必须引入React, 因为react里有一种语法叫JSX,稍后会讲到JSX,要写JSX,就必须引入React
import React from 'react'
// ReactDOM 可以帮助我们把 React 组件渲染到页面上去,没有其它的作用了。它是从 react-dom 中引入的,而不是从 react 引入。
import ReactDOM from 'react-dom'

// ReactDOM里有一个render方法,功能就是把组件渲染并且构造 DOM 树,然后插入到页面上某个特定的元素上
ReactDOM.render(
// 这里就比较奇怪了,它并不是一个字符串,看起来像是纯 HTML 代码写在 JavaScript 代码里面。语法错误吗?这并不是合法的 JavaScript 代码, “在 JavaScript 写的标签的”语法叫 JSX- JavaScript XML。
  

欢迎进入React的世界

, // 渲染到哪里 document.getElementById('root') )

四、元素与组件

如果代码多了之后,不可能一直在render方法里写,所以就需要把里面的代码提出来,定义一个变量,像这样:

import React from 'react'
import ReactDOM from 'react-dom'
// 这里感觉又不习惯了?这是在用JSX定义一下react元素
const app = 

欢迎进入React的世界

ReactDOM.render( app, document.getElementById('root') )

1、函数式组件

由于元素没有办法传递参数,所以我们就需要把之前定义的变量改为一个方法,让这个方法去return一个元素:

import React from 'react'
import ReactDOM from 'react-dom'

// 特别注意这里的写法,如果要在JSX里写js表达式(只能是表达式,不能流程控制),就需要加 {},包括注释也是一样,并且可以多层嵌套
const app = (props) => 

欢迎进入{props.name}的世界

ReactDOM.render( app({ name: 'react' }), document.getElementById('root') )

这里我们定义的方法实际上也是react定义组件的第一种方式-定义函数式组件,这也是无状态组件。但是这种写法不符合react的jsx的风格,更好的方式是使用以下方式进行改造

import React from 'react'
import ReactDOM from 'react-dom'

const App = (props) => 

欢迎进入{props.name}的世界

ReactDOM.render( // React组件的调用方式 , document.getElementById('root') )

这样一个完整的函数式组件就定义好了。但要**注意!注意!注意!*组件名必须*大写,否则报错。

react的元素(html元素)是camelcase,react组件component一定是pascalcase

2、class组件

ES6的加入让JavaScript直接支持使用class来定义一个类,react的第二种创建组件的方式就是使用的类的继承,ES6 class是目前官方推荐的使用方式,它使用了ES6标准语法来构建,看以下代码:

import React from 'react'
import ReactDOM from 'react-dom'

class App extends React.Component {
  render () {
    return (
      // 注意这里得用this.props.name, 必须用this.props
      

欢迎进入{this.props.name}的世界

) } } ReactDOM.render( , document.getElementById('root') )

运行结果和之前完全一样,因为JS里没有真正的class,这个class只是一个语法糖, 但二者的运行机制底层运行机制不一样。

  • 函数式组件是直接调用, 在前面的代码里已经有看到

  • es6 class组件其实就是一个构造器,每次使用组件都相当于在实例化组件,像这样:

    import React from 'react'
    import ReactDOM from 'react-dom'
    
    class App extends React.Component {
      render () {
        return (
      		

    欢迎进入{this.props.name}的世界

    ) } } const app = new App({ name: 'react' }).render() ReactDOM.render( app, document.getElementById('root') )

3、更老的一种方法

在16以前的版本还支持这样创建组件, 但现在的项目基本上不用

React.createClass({
  render () {
    return (
      
{this.props.xxx}
) } })

4、组件的组合、嵌套

将一个组件渲染到某一个节点里的时候,会将这个节点里原有内容覆盖

组件嵌套的方式就是将子组件写入到父组件的模板中去,且react没有Vue中的内容分发机制(slot),所以我们在一个组件的模板中只能看到父子关系

// 从 react 的包当中引入了 React 和 React.js 的组件父类 Component
// 还引入了一个React.js里的一种特殊的组件 Fragment
import React, { Component, Fragment } from 'react'
import ReactDOM from 'react-dom'

class Title extends Component {
  render () {
    return (
      

欢迎进入React的世界

) } } class Content extends Component { render () { return (

React.js是一个构建UI的库

) } } /** 由于每个React组件只能有一个根节点,所以要渲染多个组件的时候,需要在最外层包一个容器,如果使用div, 会生成多余的一层dom class App extends Component { render () { return (
<Content /> </div> ) } } **/ // 如果不想生成多余的一层dom可以使用React提供的Fragment组件在最外层进行包裹 class App extends Component { render () { return ( <Fragment> <Title /> <Content /> </Fragment> ) } } ReactDOM.render( <App/>, document.getElementById('root') ) </code></pre> <h1>五、JSX 原理</h1> <p>要明白JSX的原理,需要先明白如何用 JavaScript 对象来表现一个 DOM 元素的结构?</p> <p>看下面的DOM结构</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">'</span>app<span class="token punctuation">'</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">'</span>appRoot<span class="token punctuation">'</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">'</span>title<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>欢迎进入React的世界<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span> React.js 是一个帮助你构建页面 UI 的库 <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> </code></pre> <p>上面这个 HTML 所有的信息我们都可以用 JavaScript 对象来表示:</p> <pre><code class="prism language-json"><span class="token punctuation">{ </span> tag<span class="token punctuation">:</span> <span class="token string">'div'</span><span class="token punctuation">,</span> attrs<span class="token punctuation">:</span> <span class="token punctuation">{ </span> className<span class="token punctuation">:</span> <span class="token string">'app'</span><span class="token punctuation">,</span> id<span class="token punctuation">:</span> <span class="token string">'appRoot'</span><span class="token punctuation">}</span><span class="token punctuation">,</span> children<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{ </span> tag<span class="token punctuation">:</span> <span class="token string">'h1'</span><span class="token punctuation">,</span> attrs<span class="token punctuation">:</span> <span class="token punctuation">{ </span> className<span class="token punctuation">:</span> <span class="token string">'title'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> children<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'欢迎进入React的世界'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{ </span> tag<span class="token punctuation">:</span> <span class="token string">'p'</span><span class="token punctuation">,</span> attrs<span class="token punctuation">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span> children<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'React.js 是一个构建页面 UI 的库'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> </code></pre> <p>但是用 JavaScript 写起来太长了,结构看起来又不清晰,用 HTML 的方式写起来就方便很多了。</p> <p>于是 React.js 就把 JavaScript 的语法扩展了一下,让 JavaScript 语言能够支持这种直接在 JavaScript 代码里面编写类似 HTML 标签结构的语法,这样写起来就方便很多了。编译的过程会把类似 HTML 的 JSX 结构转换成 JavaScript 的对象结构。</p> <p>下面代码:</p> <pre><code class="prism language-jsx">import React from 'react' import ReactDOM from 'react-dom' class App extends React.Component { render () { return ( <div className='app' id='appRoot'> <h1 className='title'>欢迎进入React的世界</h1> <p> React.js 是一个构建页面 UI 的库 </p> </div> ) } } ReactDOM.render( <App />, document.getElementById('root') ) </code></pre> <p>编译之后将得到这样的代码:</p> <pre><code class="prism language-jsx">import React from 'react' import ReactDOM from 'react-dom' class App extends React.Component { render () { return ( React.createElement( "div", { className: 'app', id: 'appRoot' }, React.createElement( "h1", { className: 'title' }, "欢迎进入React的世界" ), React.createElement( "p", null, "React.js 是一个构建页面 UI 的库" ) ) ) } } ReactDOM.render( React.createElement(App), document.getElementById('root') ) </code></pre> <p><code>React.createElement</code> 会构建一个 JavaScript 对象来描述你 HTML 结构的信息,包括标签名、属性、还有子元素等, 语法为</p> <pre><code class="prism language-jsx">React.createElement( type, [props], [...children] ) </code></pre> <p>所谓的 JSX 其实就是 JavaScript 对象,所以使用 React 和 JSX 的时候一定要经过编译的过程:</p> <blockquote> <p>JSX —使用react构造组件,bable进行编译—> JavaScript对象 — <code>ReactDOM.render()</code>—>DOM元素 —>插入页面</p> </blockquote> <h1>六、组件中DOM样式</h1> <ul> <li>行内样式</li> </ul> <p>想给虚拟dom添加行内样式,需要使用表达式传入样式对象的方式来实现:</p> <pre><code class="prism language-html">// 注意这里的两个括号,第一个表示我们在要JSX里插入JS了,第二个是对象的括号 <p style={ {color:'red', fontSize:'14px'}}>Hello world<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> </code></pre> <p>行内样式需要写入一个样式对象,而这个样式对象的位置可以放在很多地方,例如<code>render</code>函数里、组件原型上、外链js文件中</p> <ul> <li>使用<code>class</code></li> </ul> <p>React推荐我们使用行内样式,因为React觉得每一个组件都是一个独立的整体</p> <p>其实我们大多数情况下还是大量的在为元素添加类名,但是需要注意的是,<code>class</code>需要写成<code>className</code>(因为毕竟是在写类js代码,会收到js规则的现在,而<code>class</code>是关键字)</p> <pre><code class="prism language-html"><p className="hello" style = {this.style}>Hello world<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> </code></pre> <ul> <li>不同的条件添加不同的样式</li> </ul> <p>有时候需要根据不同的条件添加不同的样式,比如:完成状态,完成是绿色,未完成是红色。那么这种情况下,我们推荐使用classnames这个包:</p> <ul> <li>css-in-js</li> </ul> <p><code>styled-components</code>是针对React写的一套css-in-js框架,简单来讲就是在js中写css。npm链接</p> <h1>七、组件的数据挂载方式</h1> <h2>1、属性(props)</h2> <p><code>props</code>是正常是外部传入的,组件内部也可以通过一些方式来初始化的设置,属性不能被组件自己更改,但是你可以通过父组件主动重新渲染的方式来传入新的 <code>props</code></p> <p>属性是描述性质、特点的,组件自己不能随意更改。</p> <p>之前的组件代码里面有<code>props</code>的简单使用,总的来说,在使用一个组件的时候,可以把参数放在标签的属性当中,所有的属性都会作为组件 <code>props</code> 对象的键值。通过箭头函数创建的组件,需要通过函数的参数来接收<code>props</code>:</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> Component<span class="token punctuation">,</span> Fragment <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">import</span> ReactDOM <span class="token keyword">from</span> <span class="token string">'react-dom'</span> <span class="token keyword">class</span> <span class="token class-name">Title</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> <span class="token function">render</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>h1<span class="token operator">></span>欢迎进入<span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>name<span class="token punctuation">}</span>的世界<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> <span class="token function-variable function">Content</span> <span class="token operator">=</span> <span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>p<span class="token operator">></span><span class="token punctuation">{ </span>props<span class="token punctuation">.</span>name<span class="token punctuation">}</span>是一个构建<span class="token constant">UI</span>的库<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> <span class="token function">render</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Fragment<span class="token operator">></span> <span class="token operator"><</span>Title name<span class="token operator">=</span><span class="token string">"React"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Content name<span class="token operator">=</span><span class="token string">"React.js"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Fragment<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span> <span class="token operator"><</span>App<span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">,</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'root'</span><span class="token punctuation">)</span> <span class="token punctuation">)</span> </code></pre> <h3>(1) 设置组件的默认props</h3> <pre><code class="prism language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> Component<span class="token punctuation">,</span> Fragment <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">import</span> ReactDOM <span class="token keyword">from</span> <span class="token string">'react-dom'</span> <span class="token keyword">class</span> <span class="token class-name">Title</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> <span class="token comment">// 使用类创建的组件,直接在这里写static方法,创建defaultProps</span> <span class="token keyword">static</span> defaultProps <span class="token operator">=</span> <span class="token punctuation">{ </span> name<span class="token punctuation">:</span> <span class="token string">'React'</span> <span class="token punctuation">}</span> <span class="token function">render</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>h1<span class="token operator">></span>欢迎进入<span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>name<span class="token punctuation">}</span>的世界<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> <span class="token function-variable function">Content</span> <span class="token operator">=</span> <span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>p<span class="token operator">></span><span class="token punctuation">{ </span>props<span class="token punctuation">.</span>name<span class="token punctuation">}</span>是一个构建<span class="token constant">UI</span>的库<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">// 使用箭头函数创建的组件,需要在这个组件上直接写defaultProps属性</span> Content<span class="token punctuation">.</span>defaultProps <span class="token operator">=</span> <span class="token punctuation">{ </span> name<span class="token punctuation">:</span> <span class="token string">'React.js'</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> <span class="token function">render</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Fragment<span class="token operator">></span> <span class="token punctuation">{ </span><span class="token comment">/* 由于设置了defaultProps, 不传props也能正常运行,如果传递了就会覆盖defaultProps的值 */</span><span class="token punctuation">}</span> <span class="token operator"><</span>Title <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Content <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Fragment<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span> <span class="token operator"><</span>App<span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">,</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'root'</span><span class="token punctuation">)</span> <span class="token punctuation">)</span> </code></pre> <h3>(2) props.children</h3> <p>我们知道使用组件的时候,可以嵌套。要在自定义组件的使用嵌套结构,就需要使用 <code>props.children</code> 。在实际的工作当中,我们几乎每天都需要用这种方式来编写组件。</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> Component<span class="token punctuation">,</span> Fragment <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">import</span> ReactDOM <span class="token keyword">from</span> <span class="token string">'react-dom'</span> <span class="token keyword">class</span> <span class="token class-name">Title</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> <span class="token function">render</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>h1<span class="token operator">></span>欢迎进入<span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>children<span class="token punctuation">}</span>的世界<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> <span class="token function-variable function">Content</span> <span class="token operator">=</span> <span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>p<span class="token operator">></span><span class="token punctuation">{ </span>props<span class="token punctuation">.</span>children<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> <span class="token function">render</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Fragment<span class="token operator">></span> <span class="token operator"><</span>Title<span class="token operator">></span>React<span class="token operator"><</span><span class="token operator">/</span>Title<span class="token operator">></span> <span class="token operator"><</span>Content<span class="token operator">></span><span class="token operator"><</span>i<span class="token operator">></span>React<span class="token punctuation">.</span>js<span class="token operator"><</span><span class="token operator">/</span>i<span class="token operator">></span>是一个构建<span class="token constant">UI</span>的库<span class="token operator"><</span><span class="token operator">/</span>Content<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Fragment<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span> <span class="token operator"><</span>App<span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">,</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'root'</span><span class="token punctuation">)</span> <span class="token punctuation">)</span> </code></pre> <h3>(3) 使用prop-types检查props</h3> <p>React其实是为了构建大型应用程序而生, 在一个大型应用中,根本不知道别人使用你写的组件的时候会传入什么样的参数,有可能会造成应用程序运行不了,但是不报错。为了解决这个问题,React提供了一种机制,让写组件的人可以给组件的<code>props</code>设定参数检查,需要安装和使用prop-types:</p> <pre><code>$ npm i prop-types -S </code></pre> <h2>2、状态(state)</h2> <p>状态就是组件描述某种显示情况的数据,由组件自己设置和更改,也就是说由组件自己维护,使用状态的目的就是为了在不同的状态下使组件的显示不同(自己管理)</p> <h3>(1) 定义state</h3> <p>第一种方式</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">import</span> ReactDOM <span class="token keyword">from</span> <span class="token string">'react-dom'</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> state <span class="token operator">=</span> <span class="token punctuation">{ </span> name<span class="token punctuation">:</span> <span class="token string">'React'</span><span class="token punctuation">,</span> isLiked<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span> <span class="token function">render</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>h1<span class="token operator">></span>欢迎来到<span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>name<span class="token punctuation">}</span>的世界<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>button<span class="token operator">></span> <span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>isLiked <span class="token operator">?</span> <span class="token string">'❤️取消'</span> <span class="token punctuation">:</span> <span class="token string">'收藏'</span> <span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span> <span class="token operator"><</span>App<span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">,</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'root'</span><span class="token punctuation">)</span> <span class="token punctuation">)</span> </code></pre> <p>另一种方式(推荐)</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">import</span> ReactDOM <span class="token keyword">from</span> <span class="token string">'react-dom'</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token punctuation">{ </span> name<span class="token punctuation">:</span> <span class="token string">'React'</span><span class="token punctuation">,</span> isLiked<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function">render</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>h1<span class="token operator">></span>欢迎来到<span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>name<span class="token punctuation">}</span>的世界<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>button<span class="token operator">></span> <span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>isLiked <span class="token operator">?</span> <span class="token string">'❤️取消'</span> <span class="token punctuation">:</span> <span class="token string">'收藏'</span> <span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span> <span class="token operator"><</span>App<span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">,</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'root'</span><span class="token punctuation">)</span> <span class="token punctuation">)</span> </code></pre> <p><code>this.props</code>和<code>this.state</code>是纯js对象,在vue中,data属性是利用<code>Object.defineProperty</code>处理过的,更改data的数据的时候会触发数据的<code>getter</code>和<code>setter</code>,但是React中没有做这样的处理,如果直接更改的话,react是无法得知的,所以,需要使用特殊的更改状态的方法<code>setState</code>。</p> <h3>(2) setState</h3> <p><code>isLiked</code> 存放在实例的 <code>state</code> 对象当中,组件的 <code>render</code> 函数内,会根据组件的 <code>state</code> 的中的<code>isLiked</code>不同显示“取消”或“收藏”内容。下面给 <code>button</code> 加上了点击的事件监听。</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">import</span> ReactDOM <span class="token keyword">from</span> <span class="token string">'react-dom'</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token punctuation">{ </span> name<span class="token punctuation">:</span> <span class="token string">'React'</span><span class="token punctuation">,</span> isLiked<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function-variable function">handleBtnClick</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> isLiked<span class="token punctuation">:</span> <span class="token operator">!</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>isLiked <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">render</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>h1<span class="token operator">></span>欢迎来到<span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>name<span class="token punctuation">}</span>的世界<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>handleBtnClick<span class="token punctuation">}</span><span class="token operator">></span> <span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>isLiked <span class="token operator">?</span> <span class="token string">'❤️取消'</span> <span class="token punctuation">:</span> <span class="token string">'收藏'</span> <span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span> <span class="token operator"><</span>App<span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">,</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'root'</span><span class="token punctuation">)</span> <span class="token punctuation">)</span> </code></pre> <p><code>setState</code>有两个参数</p> <p>第一个参数可以是对象,也可以是方法return一个对象,我们把这个参数叫做<code>updater</code></p> <ul> <li> <p>参数是对象</p> <pre><code class="prism language-js"><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> isLiked<span class="token punctuation">:</span> <span class="token operator">!</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>isLiked <span class="token punctuation">}</span><span class="token punctuation">)</span> </code></pre> </li> <li> <p>参数是方法</p> <pre><code class="prism language-js"><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">(</span>prevState<span class="token punctuation">,</span> props<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">{ </span> isLiked<span class="token punctuation">:</span> <span class="token operator">!</span>prevState<span class="token punctuation">.</span>isLiked <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> </code></pre> <p>注意的是这个方法接收两个参数,第一个是上一次的state, 第二个是props</p> </li> </ul> <p><code>setState</code>是异步的,所以想要获取到最新的state,没有办法获取,就有了第二个参数,这是一个可选的回调函数</p> <pre><code class="prism language-js"><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">(</span>prevState<span class="token punctuation">,</span> props<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">{ </span> isLiked<span class="token punctuation">:</span> <span class="token operator">!</span>prevState<span class="token punctuation">.</span>isLiked <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'回调里的'</span><span class="token punctuation">,</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>isLiked<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'setState外部的'</span><span class="token punctuation">,</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>isLiked<span class="token punctuation">)</span> </code></pre> <h2>3、属性vs状态</h2> <p>相似点:都是纯js对象,都会触发render更新,都具有确定性(状态/属性相同,结果相同)</p> <p>不同点:</p> <ol> <li>属性能从父组件获取,状态不能</li> <li>属性可以由父组件修改,状态不能</li> <li>属性能在内部设置默认值,状态也可以</li> <li>属性不在组件内部修改,状态要改</li> <li>属性能设置子组件初始值,状态不可以</li> <li>属性可以修改子组件的值,状态不可以</li> </ol> <p><code>state</code> 的主要作用是用于组件保存、控制、修改自己的可变状态。<code>state</code> 在组件内部初始化,可以被组件自身修改,而外部不能访问也不能修改。你可以认为 <code>state</code> 是一个局部的、只能被组件自身控制的数据源。<code>state</code> 中状态可以通过 <code>this.setState</code>方法进行更新,<code>setState</code> 会导致组件的重新渲染。</p> <p><code>props</code> 的主要作用是让使用该组件的父组件可以传入参数来配置该组件。它是外部传进来的配置参数,组件内部无法控制也无法修改。除非外部组件主动传入新的 <code>props</code>,否则组件的 <code>props</code> 永远保持不变。</p> <p>如果搞不清 <code>state</code> 和 <code>props</code> 的使用场景,记住一个简单的规则:<strong>尽量少地用 <code>state</code>,多用 <code>props</code></strong>。</p> <p>没有 <code>state</code> 的组件叫无状态组件(stateless component),设置了 state 的叫做有状态组件(stateful component)。因为状态会带来管理的复杂性,我们尽量多地写无状态组件,尽量少地写有状态的组件。这样会降低代码维护的难度,也会在一定程度上增强组件的可复用性。</p> <h2>4、状态提升</h2> <p>如果有多个组件共享一个数据,把这个数据放到共同的父级组件中来管理</p> <h2>5、受控组件与非受控组件</h2> <p>React组件的数据渲染是否被调用者传递的<code>props</code>完全控制,控制则为受控组件,否则非受控组件。</p> <h2>6、渲染数据</h2> <ul> <li>条件渲染</li> </ul> <pre><code class="prism language-js"> <span class="token punctuation">{ </span> condition <span class="token operator">?</span> <span class="token string">'❤️取消'</span> <span class="token punctuation">:</span> <span class="token string">'收藏'</span> <span class="token punctuation">}</span> </code></pre> <ul> <li>列表渲染</li> </ul> <pre><code class="prism language-jsx">// 数据 const people = [{ id: 1, name: 'Leo', age: 35 }, { id: 2, name: 'XiaoMing', age: 16 }] // 渲染列表 { people.map(person => { return ( <dl key={person.id}> <dt>{person.name}</dt> <dd>age: {person.age}</dd> </dl> ) }) } </code></pre> <p>React的高效依赖于所谓的 Virtual-DOM,尽量不碰 DOM。对于列表元素来说会有一个问题:元素可能会在一个列表中改变位置。要实现这个操作,只需要交换一下 DOM 位置就行了,但是React并不知道其实我们只是改变了元素的位置,所以它会重新渲染后面两个元素(再执行 Virtual-DOM ),这样会大大增加 DOM 操作。但如果给每个元素加上唯一的标识,React 就可以知道这两个元素只是交换了位置,这个标识就是<code>key</code>,这个 <code>key</code> 必须是每个元素唯一的标识</p> <ul> <li>dangerouslySetInnerHTML</li> </ul> <p>对于富文本创建的内容,后台拿到的数据是这样的:</p> <pre><code>content = "<p>React.js是一个构建UI的库</p>" </code></pre> <p>处于安全的原因,React当中所有表达式的内容会被转义,如果直接输入,标签会被当成文本。这时候就需要使用<code>dangerouslySetHTML</code>属性,它允许我们动态设置<code>innerHTML</code></p> <pre><code class="prism language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">import</span> ReactDOM <span class="token keyword">from</span> <span class="token string">'react-dom'</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token punctuation">{ </span> content <span class="token punctuation">:</span> <span class="token string">"<p>React.js是一个构建UI的库</p>"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function">render</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div <span class="token comment">// 注意这里是两个下下划线 __html</span> dangerouslySetInnerHTML<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">{ </span>__html<span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>content<span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span> <span class="token operator"><</span>App<span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">,</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'root'</span><span class="token punctuation">)</span> <span class="token punctuation">)</span> </code></pre> <h1>八、事件处理</h1> <h2>1、绑定事件</h2> <p>采用on+事件名的方式来绑定一个事件,注意,这里和原生的事件是有区别的,原生的事件全是小写<code>onclick</code>, React里的事件是驼峰<code>onClick</code>,<strong>React的事件并不是原生事件,而是合成事件</strong>。</p> <h2>2、事件handler的写法</h2> <ul> <li>直接在render里写行内的箭头函数(不推荐)</li> <li>在组件内使用箭头函数定义一个方法(推荐)</li> <li>直接在组件内定义一个非箭头函数的方法,然后在render里直接使用<code>onClick={this.handleClick.bind(this)}</code>(不推荐)</li> <li>直接在组件内定义一个非箭头函数的方法,然后在constructor里bind(this)(推荐)</li> </ul> <h2>3、Event 对象</h2> <p>和普通浏览器一样,事件handler会被自动传入一个 <code>event</code> 对象,这个对象和普通的浏览器 <code>event</code> 对象所包含的方法和属性都基本一致。不同的是 React中的 <code>event</code> 对象并不是浏览器提供的,而是它自己内部所构建的。它同样具有<code>event.stopPropagation</code>、<code>event.preventDefault</code> 这种常用的方法</p> <h2>4、事件的参数传递</h2> <ul> <li>在<code>render</code>里调用方法的地方外面包一层箭头函数</li> <li>在<code>render</code>里通过<code>this.handleEvent.bind(this, 参数)</code>这样的方式来传递</li> <li>通过<code>event</code>传递</li> <li><mark>比较推荐的是做一个子组件, 在父组件中定义方法,通过<code>props</code>传递到子组件中,然后在子组件件通过<code>this.props.method</code>来调用</mark></li> </ul> <h2>5、处理用户输入</h2> <pre><code class="prism language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">import</span> ReactDOM <span class="token keyword">from</span> <span class="token string">'react-dom'</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token punctuation">{ </span> xing<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span> ming<span class="token punctuation">:</span> <span class="token string">''</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function-variable function">handleInputChange</span> <span class="token operator">=</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> <span class="token punctuation">[</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>name<span class="token punctuation">]</span><span class="token punctuation">:</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">render</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> <span class="token punctuation">{ </span> xing<span class="token punctuation">,</span> ming <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>label<span class="token operator">></span> <span class="token operator"><</span>span<span class="token operator">></span>姓<span class="token punctuation">:</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"text"</span> name<span class="token operator">=</span><span class="token string">"xing"</span> value<span class="token operator">=</span><span class="token punctuation">{ </span>xing<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>handleInputChange<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>label<span class="token operator">></span> <span class="token operator"><</span>span<span class="token operator">></span>名<span class="token punctuation">:</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"text"</span> name<span class="token operator">=</span><span class="token string">"ming"</span> value<span class="token operator">=</span><span class="token punctuation">{ </span>ming<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>handleInputChange<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>p<span class="token operator">></span>欢迎您<span class="token punctuation">:</span> <span class="token punctuation">{ </span>xing<span class="token punctuation">}</span><span class="token punctuation">{ </span>ming<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span> <span class="token operator"><</span>App<span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">,</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'root'</span><span class="token punctuation">)</span> <span class="token punctuation">)</span> </code></pre> <h1>九、表单</h1> <p>在 React 里,HTML 表单元素的工作方式和其他的 DOM 元素有些不同,这是因为表单元素通常会保持一些内部的 state。例如这个纯 HTML 表单只接受一个名称:</p> <pre><code class="prism language-js"><span class="token operator"><</span>form<span class="token operator">></span> <span class="token operator"><</span>label<span class="token operator">></span> 名字<span class="token punctuation">:</span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"text"</span> name<span class="token operator">=</span><span class="token string">"name"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"submit"</span> value<span class="token operator">=</span><span class="token string">"提交"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span> </code></pre> <p>此表单具有默认的 HTML 表单行为,即在用户提交表单后浏览到新页面。如果你在 React 中执行相同的代码,它依然有效。但大多数情况下,使用 JavaScript 函数可以很方便的处理表单的提交, 同时还可以访问用户填写的表单数据。实现这种效果的标准方式是使用“受控组件”。</p> <h2>1、受控组件</h2> <p>在 HTML 中,表单元素(如、 和 )通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用<code>setState()</code>来更新。</p> <p>我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。</p> <p>例如,如果我们想让前一个示例在提交时打印出名称,我们可以将表单写为受控组件:</p> <pre><code class="prism language-js"><span class="token keyword">class</span> <span class="token class-name">NameForm</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{ </span> <span class="token function">constructor</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">super</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token punctuation">{ </span>value<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleChange <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleChange<span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleSubmit <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleSubmit<span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">handleChange</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{ </span>value<span class="token punctuation">:</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">handleSubmit</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'提交的名字: '</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>form onSubmit<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>label<span class="token operator">></span> 名字<span class="token punctuation">:</span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"text"</span> value<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>value<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>handleChange<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"submit"</span> value<span class="token operator">=</span><span class="token string">"提交"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <p>由于在表单元素上设置了 <code>value</code> 属性,因此显示的值将始终为 <code>this.state.value</code>,这使得 React 的 state 成为唯一数据源。由于 <code>handlechange</code> 在每次按键时都会执行并更新 React 的 state,因此显示的值将随着用户输入而更新。</p> <p>对于受控组件来说,输入的值始终由 React 的 state 驱动。你也可以将 value 传递给其他 UI 元素,或者通过其他事件处理函数重置,但这意味着你需要编写更多的代码。</p> <h2>2、textarea 标签</h2> <p>在 HTML 中, <code><textarea></code> 元素通过其子元素定义其文本:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>textarea</span><span class="token punctuation">></span></span> 你好, 这是在 text area 里的文本 <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>textarea</span><span class="token punctuation">></span></span> </code></pre> <p>而在 React 中,<code><textarea></code> 使用 <code>value</code> 属性代替。这样,可以使得使用 <code><textarea></code> 的表单和使用单行 input 的表单非常类似:</p> <pre><code class="prism language-js"><span class="token keyword">class</span> <span class="token class-name">EssayForm</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{ </span> <span class="token function">constructor</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">super</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token punctuation">{ </span> value<span class="token punctuation">:</span> <span class="token string">'请撰写一篇关于你喜欢的 DOM 元素的文章.'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleChange <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleChange<span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleSubmit <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleSubmit<span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">handleChange</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{ </span>value<span class="token punctuation">:</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">handleSubmit</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'提交的文章: '</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>form onSubmit<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>label<span class="token operator">></span> 文章<span class="token punctuation">:</span> <span class="token operator"><</span>textarea value<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>value<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>handleChange<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"submit"</span> value<span class="token operator">=</span><span class="token string">"提交"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <p>请注意,<code>this.state.value</code> 初始化于构造函数中,因此文本区域默认有初值。</p> <h2>3、select 标签</h2> <p>在 HTML 中,<code><select></code> 创建下拉列表标签。例如,如下 HTML 创建了水果相关的下拉列表:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>select</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>grapefruit<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>葡萄柚<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>lime<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>酸橙<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>option</span> <span class="token attr-name">selected</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>coconut<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>椰子<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>mango<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>芒果<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>select</span><span class="token punctuation">></span></span> </code></pre> <p>请注意,由于 <code>selected</code> 属性的缘故,椰子选项默认被选中。React 并不会使用 <code>selected</code> 属性,而是在根 <code>select</code> 标签上使用 <code>value</code> 属性。这在受控组件中更便捷,因为您只需要在根标签中更新它。例如:</p> <pre><code class="prism language-js"><span class="token keyword">class</span> <span class="token class-name">FlavorForm</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{ </span> <span class="token function">constructor</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">super</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token punctuation">{ </span>value<span class="token punctuation">:</span> <span class="token string">'coconut'</span><span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleChange <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleChange<span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleSubmit <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleSubmit<span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">handleChange</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{ </span>value<span class="token punctuation">:</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">handleSubmit</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'你喜欢的风味是: '</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>form onSubmit<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>label<span class="token operator">></span> 选择你喜欢的风味<span class="token punctuation">:</span> <span class="token operator"><</span>select value<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>value<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>handleChange<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>option value<span class="token operator">=</span><span class="token string">"grapefruit"</span><span class="token operator">></span>葡萄柚<span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span> <span class="token operator"><</span>option value<span class="token operator">=</span><span class="token string">"lime"</span><span class="token operator">></span>酸橙<span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span> <span class="token operator"><</span>option value<span class="token operator">=</span><span class="token string">"coconut"</span><span class="token operator">></span>椰子<span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span> <span class="token operator"><</span>option value<span class="token operator">=</span><span class="token string">"mango"</span><span class="token operator">></span>芒果<span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>select<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"submit"</span> value<span class="token operator">=</span><span class="token string">"提交"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <p>总的来说,这使得, <code><input type="text"></code>, <code><textarea></code> 和 <code><select></code>之类的标签都非常相似—它们都接受一个 <code>value</code> 属性,你可以使用它来实现受控组件。</p> <blockquote> <p>注意</p> <p>你可以将数组传递到 <code>value</code> 属性中,以支持在 <code>select</code> 标签中选择多个选项:</p> <pre><code class="prism language-js"><span class="token operator"><</span>select multiple<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token boolean">true</span><span class="token punctuation">}</span> value<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">[</span><span class="token string">'B'</span><span class="token punctuation">,</span> <span class="token string">'C'</span><span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token operator">></span> </code></pre> </blockquote> <pre><code class="prism language-js"><span class="token keyword">class</span> <span class="token class-name">MulFlavorForm</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{ </span> <span class="token function">constructor</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">super</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token punctuation">{ </span> value<span class="token punctuation">:</span> <span class="token string">"coconut"</span><span class="token punctuation">,</span> arr<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> options<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{ </span> value<span class="token punctuation">:</span> <span class="token string">"grapefruit"</span><span class="token punctuation">,</span> label<span class="token punctuation">:</span> <span class="token string">"葡萄柚"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{ </span> value<span class="token punctuation">:</span> <span class="token string">"lime"</span><span class="token punctuation">,</span> label<span class="token punctuation">:</span> <span class="token string">"酸橙"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{ </span> value<span class="token punctuation">:</span> <span class="token string">"coconut"</span><span class="token punctuation">,</span> label<span class="token punctuation">:</span> <span class="token string">"椰子"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{ </span> value<span class="token punctuation">:</span> <span class="token string">"mango"</span><span class="token punctuation">,</span> label<span class="token punctuation">:</span> <span class="token string">"芒果"</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleChange <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleChange<span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">handleChange</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">{ </span> <span class="token keyword">let</span> idx <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>arr<span class="token punctuation">.</span><span class="token function">findIndex</span><span class="token punctuation">(</span>item<span class="token operator">=></span><span class="token punctuation">{ </span> <span class="token keyword">return</span> item <span class="token operator">===</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>idx <span class="token operator">>=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>arr<span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span>idx<span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>arr<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">let</span> arr <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>arr<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{ </span>arr<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>select multiple<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token boolean">true</span><span class="token punctuation">}</span> value<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>arr<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>handleChange<span class="token punctuation">}</span><span class="token operator">></span> <span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>options<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>item<span class="token punctuation">,</span>index<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token operator"><</span>option value<span class="token operator">=</span><span class="token punctuation">{ </span>item<span class="token punctuation">.</span>value<span class="token punctuation">}</span> key<span class="token operator">=</span><span class="token punctuation">{ </span>index<span class="token punctuation">}</span><span class="token operator">></span><span class="token punctuation">{ </span>item<span class="token punctuation">.</span>label<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>select<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Test4<span class="token punctuation">;</span> </code></pre> <h2>4、处理多个输入</h2> <p>当需要处理多个 <code>input</code> 元素时,我们可以给每个元素添加 <code>name</code> 属性,并让处理函数根据 <code>event.target.name</code> 的值选择要执行的操作。</p> <pre><code class="prism language-js"><span class="token keyword">class</span> <span class="token class-name">Reservation</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{ </span> <span class="token function">constructor</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">super</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token punctuation">{ </span> isGoing<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> numberOfGuests<span class="token punctuation">:</span> <span class="token number">2</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleInputChange <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleInputChange<span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">handleInputChange</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> target <span class="token operator">=</span> event<span class="token punctuation">.</span>target<span class="token punctuation">;</span> <span class="token keyword">const</span> value <span class="token operator">=</span> target<span class="token punctuation">.</span>type <span class="token operator">===</span> <span class="token string">'checkbox'</span> <span class="token operator">?</span> target<span class="token punctuation">.</span>checked <span class="token punctuation">:</span> target<span class="token punctuation">.</span>value<span class="token punctuation">;</span> <span class="token keyword">const</span> name <span class="token operator">=</span> target<span class="token punctuation">.</span>name<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> <span class="token punctuation">[</span>name<span class="token punctuation">]</span><span class="token punctuation">:</span> value <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>form<span class="token operator">></span> <span class="token operator"><</span>label<span class="token operator">></span> 参与<span class="token punctuation">:</span> <span class="token operator"><</span>input name<span class="token operator">=</span><span class="token string">"isGoing"</span> type<span class="token operator">=</span><span class="token string">"checkbox"</span> checked<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>isGoing<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>handleInputChange<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>br <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>label<span class="token operator">></span> 来宾人数<span class="token punctuation">:</span> <span class="token operator"><</span>input name<span class="token operator">=</span><span class="token string">"numberOfGuests"</span> type<span class="token operator">=</span><span class="token string">"number"</span> value<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>numberOfGuests<span class="token punctuation">}</span> onChange<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>handleInputChange<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <h2>5、文件 input 标签</h2> <p>在 HTML 中,<code><input type="file"></code> 允许用户从存储设备中选择一个或多个文件,将其上传到服务器,或通过使用 JavaScript 的 File API 进行控制。</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> </code></pre> <p>因为它的 value 只读,所以它是 React 中的一个非受控组件。将与其他非受控组件在后续文档中一起讨论。</p> <h2>6、受控输入空值</h2> <p>在受控组件上指定 value 的 prop 会阻止用户更改输入。如果你指定了 value,但输入仍可编辑,则可能是你意外地将value 设置为 undefined 或 null。</p> <p>下面的代码演示了这一点。(输入最初被锁定,但在短时间延迟后变为可编辑。)</p> <pre><code class="prism language-js">ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token operator"><</span>input value<span class="token operator">=</span><span class="token string">"hi"</span> <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">,</span> mountNode<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token operator"><</span>input value<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">null</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">,</span> mountNode<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <h2>7、非受控组件</h2> <p>在大多数情况下,我们推荐使用 受控组件 来处理表单数据。在一个受控组件中,表单数据是由 React 组件来管理的。另一种替代方案是使用非受控组件,这时表单数据将交由 DOM 节点来处理。</p> <p>要编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,你可以 使用 ref 来从 DOM 节点中获取表单数据。</p> <p>例如,下面的代码使用非受控组件接受一个表单的值:</p> <pre><code class="prism language-js"><span class="token keyword">class</span> <span class="token class-name">NameForm</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{ </span> <span class="token function">constructor</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">super</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleSubmit <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleSubmit<span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>input <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">createRef</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">handleSubmit</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'A name was submitted: '</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>input<span class="token punctuation">.</span>current<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>form onSubmit<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>label<span class="token operator">></span> Name<span class="token punctuation">:</span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"text"</span> ref<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>input<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"submit"</span> value<span class="token operator">=</span><span class="token string">"Submit"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <p>因为非受控组件将真实数据储存在 DOM 节点中,所以在使用非受控组件时,有时候反而更容易同时集成 React 和非 React 代码。如果你不介意代码美观性,并且希望快速编写代码,使用非受控组件往往可以减少你的代码量。否则,你应该使用受控组件。</p> <h3>(1) 默认值</h3> <p>在 React 渲染生命周期时,表单元素上的 <code>value</code> 将会覆盖 DOM 节点中的值,在非受控组件中,你经常希望 React 能赋予组件一个初始值,但是不去控制后续的更新。 在这种情况下, 你可以指定一个 <code>defaultValue</code> 属性,而不是 <code>value</code>。</p> <pre><code class="prism language-js"><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>form onSubmit<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>label<span class="token operator">></span> Name<span class="token punctuation">:</span> <span class="token operator"><</span>input defaultValue<span class="token operator">=</span><span class="token string">"Bob"</span> type<span class="token operator">=</span><span class="token string">"text"</span> ref<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>input<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"submit"</span> value<span class="token operator">=</span><span class="token string">"Submit"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>同样,<code><input type="checkbox"></code> 和 <code><input type="radio"></code> 支持 <code>defaultChecked</code>,<code><select></code> 和 <code><textarea></code> 支持 <code>defaultValue</code>。</p> <h3>(2) 文件输入</h3> <p>在 HTML 中,<code><input type="file"></code> 可以让用户选择一个或多个文件上传到服务器,或者通过使用 File API 进行操作。</p> <p>在 React 中,<code><input type="file"></code> 始终是一个非受控组件,因为它的值只能由用户设置,而不能通过代码控制。</p> <p>您应该使用 File API 与文件进行交互。下面的例子显示了如何创建一个 DOM 节点的 ref 从而在提交表单时获取文件的信息。</p> <pre><code class="prism language-js"><span class="token keyword">class</span> <span class="token class-name">FileInput</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{ </span> <span class="token function">constructor</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">super</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleSubmit <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleSubmit<span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>fileInput <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">createRef</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">handleSubmit</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token punctuation">{ </span> event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">alert</span><span class="token punctuation">(</span> <span class="token template-string"><span class="token string">`Selected file - </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${ </span><span class="token keyword">this</span><span class="token punctuation">.</span>fileInput<span class="token punctuation">.</span>current<span class="token punctuation">.</span>files<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>form onSubmit<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>handleSubmit<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>label<span class="token operator">></span> Upload file<span class="token punctuation">:</span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"file"</span> ref<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>fileInput<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span> <span class="token operator"><</span>br <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>button type<span class="token operator">=</span><span class="token string">"submit"</span><span class="token operator">></span>Submit<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span> <span class="token operator"><</span>FileInput <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">,</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'root'</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <h1>十、TodoList</h1> <p>组件化开发React todolist, 项目开发中的组件的基本目录结构基本上是这样的:</p> <blockquote> <p>/your-project</p> <ul> <li>src <ul> <li>…</li> <li>components <ul> <li>YourComponentOne <ul> <li>index.js/YourComponentOne.js</li> </ul> </li> <li>YourComponentTwo <ul> <li>index.js/YourComponentTwo.js</li> </ul> </li> <li>index.js 用于导出组件</li> </ul> </li> </ul> </li> </ul> </blockquote> <p>注意:一个组件只干一件事情 ,所以TodoList和TodoItem要做成两个组件,这样也方便于后期理解shouldComponentUpdate</p> <h1>十一、组件的生命周期</h1> <p>React中组件也有生命周期,也就是说也有很多钩子函数供我们使用, 组件的生命周期,我们会分为四个阶段,初始化、运行中、销毁、错误处理(16.3之后)</p> <h2>1、初始化</h2> <p>在组件初始化阶段会执行</p> <ol> <li>constructor</li> <li>static getDerivedStateFromProps()</li> <li>componentWillMount() / UNSAFE_componentWillMount()</li> <li>render()</li> <li>componentDidMount()</li> </ol> <h2>2、更新阶段</h2> <p><code>props</code>或<code>state</code>的改变可能会引起组件的更新,组件重新渲染的过程中会调用以下方法:</p> <ol> <li>componentWillReceiveProps() / UNSAFE_componentWillReceiveProps()</li> <li>static getDerivedStateFromProps()</li> <li>shouldComponentUpdate()</li> <li>componentWillUpdate() / UNSAFE_componentWillUpdate()</li> <li>render()</li> <li>getSnapshotBeforeUpdate()</li> <li>componentDidUpdate()</li> </ol> <h2>3、卸载阶段</h2> <ol> <li>componentWillUnmount()</li> </ol> <h2>4、错误处理</h2> <ol> <li>componentDidCatch()</li> </ol> <h2>5、各生命周期详解</h2> <p><strong>(1) constructor(props)</strong></p> <p>React组件的构造函数在挂载之前被调用。在实现<code>React.Component</code>构造函数时,需要先在添加其他内容前,调用<code>super(props)</code>,用来将父组件传来的<code>props</code>绑定到这个类中,使用<code>this.props</code>将会得到。</p> <p>官方建议不要在<code>constructor</code>引入任何具有副作用和订阅功能的代码,这些应当使用<code>componentDidMount()</code>。</p> <p><code>constructor</code>中应当做些初始化的动作,如:初始化<code>state</code>,将事件处理函数绑定到类实例上,但也不要使用<code>setState()</code>。如果没有必要初始化state或绑定方法,则不需要构造<code>constructor</code>,或者把这个组件换成纯函数写法。</p> <p>当然也可以利用<code>props</code>初始化<code>state</code>,在之后修改<code>state</code>不会对<code>props</code>造成任何修改,但仍然建议大家提升状态到父组件中,或使用<code>redux</code>统一进行状态管理。</p> <pre><code>constructor(props) { super(props); this.state = { isLiked: props.isLiked }; } </code></pre> <p><strong>(2) static getDerivedStateFromProps(nextProps, prevState)</strong></p> <p>React 的 16.3 版本中对生命周期进行了较大的调整,这是为了开发者能正确地使用生命周期,避免误解其概念而造成反模式。</p> <p>本节将重点介绍 getDerivedStateFromProps 这个生命周期。要注意的是,React 16.3 的版本中 getDerivedStateFromProps 的触发范围是和 16.4^ 是不同的,主要区别是在 <code>setState</code> 和 <code>forceUpdate</code> 时会不会触发,具体可以看这个生命全周期图 。</p> <p>可能的使用场景有两个:</p> <ul> <li>无条件的根据 prop 来更新内部 state,也就是只要有传入 prop 值, 就更新 state</li> <li>只有 prop 值和 state 值不同时才更新 state 值。</li> </ul> <p>我们接下来看几个例子。</p> <p>假设我们有个一个表格组件,它会根据传入的列表数据来更新视图。</p> <pre><code class="prism language-js"><span class="token keyword">class</span> <span class="token class-name">Table</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{ </span> state <span class="token operator">=</span> <span class="token punctuation">{ </span> list<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token keyword">static</span> <span class="token function">getDerivedStateFromProps</span> <span class="token punctuation">(</span>props<span class="token punctuation">,</span> state<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">{ </span> list<span class="token punctuation">:</span> props<span class="token punctuation">.</span>list <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function">render</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token operator">...</span><span class="token punctuation">.</span> <span class="token comment">// 展示 list</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <p>上面的例子就是第一种使用场景,但是无条件从 prop 中更新 state,我们完全没必要使用这个生命周期,直接对 prop 值进行操作就好了,无需用 state 值类保存。</p> <p>再看一个例子,这个例子是一个颜色选择器,这个组件能选择相应的颜色并显示,同时它能根据传入 prop 值显示颜色。</p> <pre><code class="prism language-js">Class <span class="token class-name">ColorPicker</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{ </span> state <span class="token operator">=</span> <span class="token punctuation">{ </span> color<span class="token punctuation">:</span> <span class="token string">'#000000'</span> <span class="token punctuation">}</span> <span class="token keyword">static</span> <span class="token function">getDerivedStateFromProps</span> <span class="token punctuation">(</span>props<span class="token punctuation">,</span> state<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">if</span> <span class="token punctuation">(</span>props<span class="token punctuation">.</span>color <span class="token operator">!==</span> state<span class="token punctuation">.</span>color<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">{ </span> color<span class="token punctuation">:</span> props<span class="token punctuation">.</span>color <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token keyword">null</span> <span class="token punctuation">}</span> <span class="token operator">...</span> <span class="token comment">// 选择颜色方法</span> <span class="token function">render</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token operator">...</span><span class="token punctuation">.</span> <span class="token comment">// 显示颜色和选择颜色操作</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <p>现在我们可以这个颜色选择器来选择颜色,同时我们能传入一个颜色值并显示。但是这个组件有一个 bug,如果我们传入一个颜色值后,再使用组件内部的选择颜色方法,我们会发现颜色不会变化,一直是传入的颜色值。</p> <p>这是使用这个生命周期的一个常见 bug。为什么会发生这个 bug 呢?在开头有说到,在 React 16.4^ 的版本中 <code>setState</code> 和 <code>forceUpdate</code> 也会触发这个生命周期,所以内部 state 变化后,又会走 getDerivedStateFromProps 方法,并把 state 值更新为传入的 prop。</p> <p>接下里我们来修复这个bug。</p> <pre><code class="prism language-js">Class <span class="token class-name">ColorPicker</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{ </span> state <span class="token operator">=</span> <span class="token punctuation">{ </span> color<span class="token punctuation">:</span> <span class="token string">'#000000'</span><span class="token punctuation">,</span> prevPropColor<span class="token punctuation">:</span> <span class="token string">''</span> <span class="token punctuation">}</span> <span class="token keyword">static</span> <span class="token function">getDerivedStateFromProps</span> <span class="token punctuation">(</span>props<span class="token punctuation">,</span> state<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">if</span> <span class="token punctuation">(</span>props<span class="token punctuation">.</span>color <span class="token operator">!==</span> state<span class="token punctuation">.</span>prevPropColor<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">{ </span> color<span class="token punctuation">:</span> props<span class="token punctuation">.</span>color prevPropColor<span class="token punctuation">:</span> props<span class="token punctuation">.</span>color <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token keyword">null</span> <span class="token punctuation">}</span> <span class="token operator">...</span> <span class="token comment">// 选择颜色方法</span> <span class="token function">render</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token operator">...</span><span class="token punctuation">.</span> <span class="token comment">// 显示颜色和选择颜色操作</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <p>通过保存一个之前 prop 值,我们就可以在只有 prop 变化时才去修改 state。这样就解决上述的问题。</p> <p>这里小结下 getDerivedStateFromProps 方法使用的注意点:</p> <ul> <li>在使用此生命周期时,要注意把传入的 prop 值和之前传入的 prop 进行比较。</li> <li>因为这个生命周期是静态方法,同时要保持它是纯函数,不要产生副作用。</li> </ul> <p>我们应该谨慎地使用 getDerivedStateFromProps 这个生命周期。使用时要注意下面几点:</p> <ul> <li>因为这个生命周期是静态方法,同时要保持它是纯函数,不要产生副作用。</li> <li>在使用此生命周期时,要注意把传入的 prop 值和之前传入的 prop 进行比较(这个 prop 值最好有唯一性,或者使用一个唯一性的 prop 值来专门比较)。</li> <li>不使用 getDerivedStateFromProps,可以改成组件保持完全不可控模式,通过初始值和 key 值来实现 prop 改变 state 的情景。</li> </ul> <p><strong>(3) componentWillMount() / UNSAFE_componentWillMount()</strong></p> <p><code>componentWillMount()</code>将在React未来版本(官方说法 17.0)中被弃用。<code>UNSAFE_componentWillMount()</code>在组件挂载前被调用,在这个方法中调用<code>setState()</code>不会起作用,是由于他在<code>render()</code>前被调用。</p> <p>为了避免副作用和其他的订阅,官方都建议使用<code>componentDidMount()</code>代替。这个方法是用于在服务器渲染上的唯一方法。这个方法因为是在渲染之前被调用,也是惟一一个可以直接同步修改state的地方。</p> <p><strong>(4) render()</strong></p> <p>render()方法是必需的。当他被调用时,他将计算<code>this.props</code>和<code>this.state</code>,并返回以下一种类型:</p> <ul> <li>React元素。通过jsx创建,既可以是dom元素,也可以是用户自定义的组件。</li> <li>字符串或数字。他们将会以文本节点形式渲染到dom中。</li> <li>Portals。react 16版本中提出的新的解决方案,可以使组件脱离父组件层级直接挂载在DOM树的任何位置。</li> <li>null,什么也不渲染</li> <li>布尔值。也是什么都不渲染。</li> </ul> <p>当返回<code>null</code>,<code>false</code>,<code>ReactDOM.findDOMNode(this)</code>将会返回null,什么都不会渲染。</p> <p><code>render()</code>方法必须是一个纯函数,他不应该改变<code>state</code>,也不能直接和浏览器进行交互,应该将事件放在其他生命周期函数中。 如果<code>shouldComponentUpdate()</code>返回<code>false</code>,<code>render()</code>不会被调用。</p> <p><strong>(5) componentDidMount</strong></p> <p><code>componentDidMount</code>在组件被装配后立即调用。初始化使得DOM节点应该进行到这里。</p> <p><strong>通常在这里进行ajax请求</strong></p> <p>如果要初始化第三方的dom库,也在这里进行初始化。只有到这里才能获取到真实的dom.</p> <p><strong>(6) componentWillReceiveProps()/UNSAFE_componentWillReceiveProps(nextProps)</strong></p> <p>官方建议使用<code>getDerivedStateFromProps</code>函数代替<code>componentWillReceiveProps</code>。当组件挂载后,接收到新的<code>props</code>后会被调用。如果需要更新<code>state</code>来响应<code>props</code>的更改,则可以进行<code>this.props</code>和<code>nextProps</code>的比较,并在此方法中使用<code>this.setState()</code>。</p> <p>==如果父组件会让这个组件重新渲染,即使<code>props</code>没有改变,也会调用这个方法。==所以性能差</p> <p>React不会在组件初始化props时调用这个方法。调用<code>this.setState</code>也不会触发。</p> <p><strong>(7) shouldComponentUpdate(nextProps, nextState)</strong></p> <p>调用<code>shouldComponentUpdate</code>使React知道,组件的输出是否受<code>state</code>和<code>props</code>的影响。默认每个状态的更改都会重新渲染,大多数情况下应该保持这个默认行为。</p> <p>在渲染新的<code>props</code>或<code>state</code>前,<code>shouldComponentUpdate</code>会被调用。默认为<code>true</code>。这个方法不会在初始化时被调用,也不会在<code>forceUpdate()</code>时被调用。返回<code>false</code>不会阻止子组件在<code>state</code>更改时重新渲染。</p> <p>如果<code>shouldComponentUpdate()</code>返回<code>false</code>,<code>componentWillUpdate</code>,<code>render</code>和<code>componentDidUpdate</code>不会被调用。</p> <blockquote> <p>官方并不建议在<code>shouldComponentUpdate()</code>中进行深度查询或使用<code>JSON.stringify()</code>,他效率非常低,并且损伤性能。</p> </blockquote> <p><strong>(8) UNSAFE_componentWillUpdate(nextProps, nextState)</strong></p> <p>在渲染新的<code>state</code>或<code>props</code>时,<code>UNSAFE_componentWillUpdate</code>会被调用,将此作为在更新发生之前进行准备的机会。这个方法不会在初始化时被调用。</p> <p><em>不能在这里使用this.setState()</em>,也不能做会触发视图更新的操作。如果需要更新<code>state</code>或<code>props</code>,调用<code>getDerivedStateFromProps</code>。</p> <p><strong>(9) getSnapshotBeforeUpdate()</strong></p> <p>在react <code>render()</code>后的输出被渲染到DOM之前被调用。它使您的组件能够在它们被潜在更改之前捕获当前值(如滚动位置)。这个生命周期返回的任何值都将作为参数传递给componentDidUpdate()。</p> <p><strong>(10) componentDidUpdate(prevProps, prevState, snapshot)</strong></p> <p>在更新发生后立即调用<code>componentDidUpdate()</code>。此方法不用于初始渲染。当组件更新时,将此作为一个机会来操作DOM。只要您将当前的props与以前的props进行比较(例如,如果props没有改变,则可能不需要网络请求),这也是做网络请求的好地方。</p> <p>如果组件实现<code>getSnapshotBeforeUpdate()</code>生命周期,则它返回的值将作为第三个“快照”参数传递给<code>componentDidUpdate()</code>。否则,这个参数是<code>undefined</code>。</p> <p><strong>(11) componentWillUnmount()</strong></p> <p>在组件被卸载并销毁之前立即被调用。在此方法中执行任何必要的清理,例如使定时器无效,取消网络请求或清理在<code>componentDidMount</code>中创建的任何监听。</p> <p><strong>(12) componentDidCatch(error, info)</strong></p> <p>错误边界是React组件,可以在其子组件树中的任何位置捕获JavaScript错误,记录这些错误并显示回退UI,而不是崩溃的组件树。错误边界在渲染期间,生命周期方法以及整个树下的构造函数中捕获错误。</p> <p>如果类组件定义了此生命周期方法,则它将成错误边界。在它中调用<code>setState()</code>可以让你在下面的树中捕获未处理的JavaScript错误,并显示一个后备UI。只能使用错误边界从意外异常中恢复; 不要试图将它们用于控制流程。</p> <p>错误边界只会捕获树中下面组件中的错误。错误边界本身不能捕获错误。</p> <h2>6、PureComponent</h2> <p><code>PureComponnet</code>里如果接收到的新属性或者是更改后的状态和原属性、原状态相同的话,就不会去重新render了 在里面也可以使用<code>shouldComponentUpdate</code>,而且。是否重新渲染以<code>shouldComponentUpdate</code>的返回值为最终的决定因素。</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> PureComponent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">class</span> <span class="token class-name">YourComponent</span> <span class="token keyword">extends</span> <span class="token class-name">PureComponent</span> <span class="token punctuation">{ </span> …… <span class="token punctuation">}</span> </code></pre> <h2>7、ref</h2> <p>React提供的这个<code>ref</code>属性,表示为对组件真正实例的引用,其实就是<code>ReactDOM.render()</code>返回的组件实例,<code>ref</code>可以挂载到组件上也可以是dom元素上。</p> <ul> <li>挂到组件(<code>class</code>声明的组件)上的ref表示对组件实例的引用。<strong>不能</strong>在函数式组件上使用 ref 属性,因为它们没有实例:</li> <li>挂载到dom元素上时表示具体的dom元素节点。</li> </ul> <p>在React 最新的版本中,要使用<code>ref</code>, 需要使用<code>React.createRef</code>方法先生成一个<code>ref</code>。</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> Component<span class="token punctuation">,</span> createRef <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">import</span> ReactDOM <span class="token keyword">from</span> <span class="token string">'react-dom'</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 创建inputRef</span> <span class="token keyword">this</span><span class="token punctuation">.</span>inputRef <span class="token operator">=</span> <span class="token function">createRef</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">componentDidMount</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>inputRef<span class="token punctuation">.</span>current<span class="token punctuation">)</span> <span class="token comment">// <input type="text"></span> <span class="token punctuation">}</span> <span class="token function">render</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token punctuation">{ </span><span class="token comment">/* 关联ref和dom */</span><span class="token punctuation">}</span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"text"</span> ref<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>inputRef<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span> <span class="token operator"><</span>App<span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">,</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'root'</span><span class="token punctuation">)</span> <span class="token punctuation">)</span> </code></pre> <h1>十二、组件通信</h1> <p><strong>父组件与子组件通信</strong></p> <ul> <li>父组件将自己的状态传递给子组件,子组件当做属性来接收,当父组件更改自己状态的时候,子组件接收到的属性就会发生改变</li> <li>父组件利用<code>ref</code>对子组件做标记,通过调用子组件的方法以更改子组件的状态,也可以调用子组件的方法…</li> </ul> <p><strong>子组件与父组件通信</strong></p> <ul> <li>父组件将自己的某个方法传递给子组件,在方法里可以做任意操作,比如可以更改状态,子组件通过<code>this.props</code>接收到父组件的方法后调用。</li> </ul> <p><strong>跨组件通信</strong></p> <p>在react没有类似vue中的事件总线来解决这个问题,我们只能借助它们共同的父级组件来实现,将非父子关系装换成多维度的父子关系。react提供了<code>context</code> api来实现跨组件通信, React 16.3之后的<code>context</code>api较之前的好用。</p> <p>实例,使用<code>context</code> 实现购物车中的加减功能</p> <pre><code class="prism language-js"><span class="token comment">// counterContext.js</span> <span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> Component<span class="token punctuation">,</span> createContext <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">const</span> <span class="token punctuation">{ </span> Provider<span class="token punctuation">,</span> Consumer<span class="token punctuation">:</span> CountConsumer <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">createContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">class</span> <span class="token class-name">CountProvider</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> <span class="token function">constructor</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token punctuation">{ </span> count<span class="token punctuation">:</span> <span class="token number">1</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function-variable function">increaseCount</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> count<span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>count <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function-variable function">decreaseCount</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> count<span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>count <span class="token operator">-</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Provider value<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">{ </span> count<span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>count<span class="token punctuation">,</span> increaseCount<span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>increaseCount<span class="token punctuation">,</span> decreaseCount<span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>decreaseCount <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">></span> <span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>children<span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>Provider<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token punctuation">{ </span> CountProvider<span class="token punctuation">,</span> CountConsumer <span class="token punctuation">}</span> <span class="token comment">// 定义CountButton组件</span> <span class="token keyword">const</span> <span class="token function-variable function">CountButton</span> <span class="token operator">=</span> <span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>CountConsumer<span class="token operator">></span> <span class="token comment">// consumer的children必须是一个方法</span> <span class="token punctuation">{ </span> <span class="token punctuation">(</span><span class="token punctuation">{ </span> increaseCount<span class="token punctuation">,</span> decreaseCount <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> <span class="token punctuation">{ </span> type <span class="token punctuation">}</span> <span class="token operator">=</span> props <span class="token keyword">const</span> handleClick <span class="token operator">=</span> type <span class="token operator">===</span> <span class="token string">'increase'</span> <span class="token operator">?</span> increaseCount <span class="token punctuation">:</span> decreaseCount <span class="token keyword">const</span> btnText <span class="token operator">=</span> type <span class="token operator">===</span> <span class="token string">'increase'</span> <span class="token operator">?</span> <span class="token string">'+'</span> <span class="token punctuation">:</span> <span class="token string">'-'</span> <span class="token keyword">return</span> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{ </span>handleClick<span class="token punctuation">}</span><span class="token operator">></span><span class="token punctuation">{ </span>btnText<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>CountConsumer<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">// 定义count组件,用于显示数量</span> <span class="token keyword">const</span> <span class="token function-variable function">Count</span> <span class="token operator">=</span> <span class="token punctuation">(</span>prop<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>CountConsumer<span class="token operator">></span> <span class="token punctuation">{ </span> <span class="token punctuation">(</span><span class="token punctuation">{ </span> count <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token operator"><</span>span<span class="token operator">></span><span class="token punctuation">{ </span>count<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>CountConsumer<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">// 组合</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> <span class="token function">render</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>CountProvider<span class="token operator">></span> <span class="token operator"><</span>CountButton type<span class="token operator">=</span><span class="token string">'decrease'</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>Count <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>CountButton type<span class="token operator">=</span><span class="token string">'increase'</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>CountProvider<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <blockquote> <p>复杂的非父子组件通信在react中很难处理,多组件间的数据共享也不好处理,在实际的工作中我们会使用flux、redux、mobx来实现</p> </blockquote> <h1>十三、HOC(高阶组件)</h1> <p>Higher-Order Components就是一个函数,传给它一个组件,它返回一个新的组件。</p> <pre><code class="prism language-js"><span class="token keyword">const</span> NewComponent <span class="token operator">=</span> <span class="token function">higherOrderComponent</span><span class="token punctuation">(</span>YourComponent<span class="token punctuation">)</span> </code></pre> <p>比如,我们想要我们的组件通过自动注入一个版权信息。</p> <pre><code class="prism language-js"><span class="token comment">// withCopyright.js 定义一个高阶组件</span> <span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> Component<span class="token punctuation">,</span> Fragment <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">const</span> <span class="token function-variable function">withCopyright</span> <span class="token operator">=</span> <span class="token punctuation">(</span>WrappedComponent<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token keyword">class</span> <span class="token class-name">NewComponent</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Fragment<span class="token operator">></span> <span class="token operator"><</span>WrappedComponent <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>div<span class="token operator">></span><span class="token operator">&</span>copy<span class="token punctuation">;</span>版权所有 千锋教育 <span class="token number">2019</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Fragment<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> withCopyright <span class="token comment">// 使用方式</span> <span class="token keyword">import</span> withCopyright <span class="token keyword">from</span> <span class="token string">'./withCopyright'</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> <span class="token function">render</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>h1<span class="token operator">></span>Awesome React<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>p<span class="token operator">></span>React<span class="token punctuation">.</span>js是一个构建用户界面的库<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> CopyrightApp <span class="token operator">=</span> <span class="token function">withCopyright</span><span class="token punctuation">(</span>App<span class="token punctuation">)</span> </code></pre> <p>这样只要我们有需要用到版权信息的组件,都可以直接使用withCopyright这个高阶组件包裹即可。</p> <p>在这里要讲解在CRA 中配置装饰器模式的支持。</p> <h1>十四、Portal</h1> <p>Portals 提供了一个最好的在父组件包含的DOM结构层级外的DOM节点渲染组件的方法。</p> <pre><code class="prism language-js">ReactDOM<span class="token punctuation">.</span><span class="token function">createPortal</span><span class="token punctuation">(</span>child<span class="token punctuation">,</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <p>第一个参数child是可渲染的react子项,比如元素,字符串或者片段等。第二个参数container是一个DOM元素。</p> <h2>1、用法</h2> <p>普通的组件,子组件的元素将挂载到父组件的DOM节点中。</p> <pre><code class="prism language-js"><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token comment">// React 挂载一个div节点,并将子元素渲染在节点中</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>children<span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>有时需要将元素渲染到DOM中的不同位置上去,这是就用到的portal的方法。</p> <pre><code class="prism language-jsx">render(){ // 此时React不再创建div节点,而是将子元素渲染到Dom节点上。domNode,是一个有效的任意位置的dom节点。 return ReactDOM.createPortal( this.props.children, domNode ) } </code></pre> <p>一个典型的用法就是当父组件的dom元素有 <code>overflow:hidden</code>或者<code>z-inde</code>样式,而你又需要显示的子元素超出父元素的盒子。举例来说,如对话框,悬浮框,和小提示。</p> <h2>2、在protal中的事件冒泡</h2> <p>虽然通过portal渲染的元素在父组件的盒子之外,但是渲染的dom节点仍在React的元素树上,在那个dom元素上的点击事件仍然能在dom树中监听到。</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> ReactDOM <span class="token keyword">from</span> <span class="token string">'react-dom'</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">getDiv</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> div <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>div<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> div<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">withPortal</span> <span class="token operator">=</span> <span class="token punctuation">(</span>WrappedComponent<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">class</span> <span class="token class-name">AddPortal</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> <span class="token function">constructor</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">super</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>el <span class="token operator">=</span> <span class="token function">getDiv</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">componentWillUnmount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">removeChild</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>el<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">render</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> ReactDOM<span class="token punctuation">.</span><span class="token function">createPortal</span><span class="token punctuation">(</span><span class="token operator"><</span>WrappedComponent <span class="token punctuation">{ </span><span class="token operator">...</span>props<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>el<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> AddPortal<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Modal</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>div<span class="token operator">></span>amodal content<span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>button type<span class="token operator">=</span><span class="token string">"button"</span><span class="token operator">></span>Click<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> PortalModal <span class="token operator">=</span> <span class="token function">withPortal</span><span class="token punctuation">(</span>Modal<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Page</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> <span class="token function">constructor</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">super</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token punctuation">{ </span> clicks<span class="token punctuation">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleClick <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handleClick<span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">handleClick</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span>state <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">{ </span> clicks<span class="token punctuation">:</span> state<span class="token punctuation">.</span>clicks <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div onClick<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>handleClick<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>h3<span class="token operator">></span>ppppppppp<span class="token operator"><</span><span class="token operator">/</span>h3<span class="token operator">></span> <span class="token operator"><</span>h3<span class="token operator">></span>num<span class="token punctuation">:</span> <span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>clicks<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>h3<span class="token operator">></span> <span class="token operator"><</span>PortalModal <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Page<span class="token punctuation">;</span> </code></pre> <h1>十五、状态管理</h1> <h2>1、传统MVC框架的缺陷</h2> <p><strong>什么是MVC?</strong></p> <p><a href="http://img.e-com-net.com/image/info8/98c183c1a337432f9f8738691ca79107.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/98c183c1a337432f9f8738691ca79107.jpg" alt="2021react复习_第1张图片" width="650" height="282" style="border:1px solid black;"></a></p> <p><code>MVC</code>的全名是<code>Model View Controller</code>,是模型(model)-视图(view)-控制器(controller)的缩写,是一种软件设计典范。</p> <p><code>V</code>即View视图是指用户看到并与之交互的界面。</p> <p><code>M</code>即Model模型是管理数据 ,很多业务逻辑都在模型中完成。在MVC的三个部件中,模型拥有最多的处理任务。</p> <p><code>C</code>即Controller控制器是指控制器接受用户的输入并调用模型和视图去完成用户的需求,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。</p> <p><strong>MVC只是看起来很美</strong></p> <p>MVC框架的数据流很理想,请求先到Controller, 由Controller调用Model中的数据交给View进行渲染,但是在实际的项目中,又是允许Model和View直接通信的。然后就出现了这样的结果:</p> <p><a href="http://img.e-com-net.com/image/info8/d771b6fdd7de4ca2b5f9303cbd8e1a90.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/d771b6fdd7de4ca2b5f9303cbd8e1a90.jpg" alt="2021react复习_第2张图片" width="650" height="277" style="border:1px solid black;"></a></p> <h2>2、Flux</h2> <p>在2013年,Facebook让<code>React</code>亮相的同时推出了Flux框架,<code>React</code>的初衷实际上是用来替代<code>jQuery</code>的,<code>Flux</code>实际上就可以用来替代<code>Backbone.js</code>,<code>Ember.js</code>等一系列<code>MVC</code>架构的前端JS框架。</p> <p>其实<code>Flux</code>在<code>React</code>里的应用就类似于<code>Vue</code>中的<code>Vuex</code>的作用,但是在<code>Vue</code>中,<code>Vue</code>是完整的<code>mvvm</code>框架,而<code>Vuex</code>只是一个全局的插件。</p> <p><code>React</code>只是一个MVC中的V(视图层),只管页面中的渲染,一旦有数据管理的时候,<code>React</code>本身的能力就不足以支撑复杂组件结构的项目,在传统的<code>MVC</code>中,就需要用到Model和Controller。Facebook对于当时世面上的<code>MVC</code>框架并不满意,于是就有了<code>Flux</code>, 但<code>Flux</code>并不是一个<code>MVC</code>框架,他是一种新的思想。</p> <p><a href="http://img.e-com-net.com/image/info8/06595ea2c8274937bd4a81e2ee9f9bf7.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/06595ea2c8274937bd4a81e2ee9f9bf7.jpg" alt="2021react复习_第3张图片" width="650" height="149" style="border:1px solid black;"></a></p> <ul> <li>View: 视图层</li> <li>ActionCreator(动作创造者):视图层发出的消息(比如mouseClick)</li> <li>Dispatcher(派发器):用来接收Actions、执行回调函数</li> <li>Store(数据层):用来存放应用的状态,一旦发生变动,就提醒Views要更新页面</li> </ul> <p>Flux的流程:</p> <ol> <li>组件获取到store中保存的数据挂载在自己的状态上</li> <li>用户产生了操作,调用actions的方法</li> <li>actions接收到了用户的操作,进行一系列的逻辑代码、异步操作</li> <li>然后actions会创建出对应的action,action带有标识性的属性</li> <li>actions调用dispatcher的dispatch方法将action传递给dispatcher</li> <li>dispatcher接收到action并根据标识信息判断之后,调用store的更改数据的方法</li> <li>store的方法被调用后,更改状态,并触发自己的某一个事件</li> <li>store更改状态后事件被触发,该事件的处理程序会通知view去获取最新的数据</li> </ol> <h2>3、Redux</h2> <p>React 只是 DOM 的一个抽象层,并不是 Web 应用的完整解决方案。有两个方面,它没涉及。</p> <ul> <li>代码结构</li> <li>组件之间的通信</li> </ul> <p>2013年 Facebook 提出了 Flux 架构的思想,引发了很多的实现。2015年,Redux 出现,将 Flux 与函数式编程结合一起,很短时间内就成为了最热门的前端架构。</p> <p>如果你不知道是否需要 Redux,那就是不需要它</p> <p>只有遇到 React 实在解决不了的问题,你才需要 Redux</p> <p>简单说,如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加复杂性。</p> <ul> <li>用户的使用方式非常简单</li> <li>用户之间没有协作</li> <li>不需要与服务器大量交互,也没有使用 WebSocket</li> <li>视图层(View)只从单一来源获取数据</li> </ul> <p><strong>需要使用Redux的项目:</strong></p> <ul> <li>用户的使用方式复杂</li> <li>不同身份的用户有不同的使用方式(比如普通用户和管理员)</li> <li>多个用户之间可以协作</li> <li>与服务器大量交互,或者使用了WebSocket</li> <li>View要从多个来源获取数据</li> </ul> <p><strong>从组件层面考虑,什么样子的需要Redux:</strong></p> <ul> <li>某个组件的状态,需要共享</li> <li>某个状态需要在任何地方都可以拿到</li> <li>一个组件需要改变全局状态</li> <li>一个组件需要改变另一个组件的状态</li> </ul> <p><strong>Redux的设计思想:</strong></p> <ol> <li>Web 应用是一个状态机,视图与状态是一一对应的。</li> <li>所有的状态,保存在一个对象里面(唯一数据源)。</li> </ol> <blockquote> <p>注意:flux、redux都不是必须和react搭配使用的,因为flux和redux是完整的架构,在学习react的时候,只是将react的组件作为redux中的视图层去使用了。</p> </blockquote> <p><strong>Redux的使用的三大原则:</strong></p> <ul> <li>Single Source of Truth(唯一的数据源)</li> <li>State is read-only(状态是只读的)</li> <li>Changes are made with pure function(数据的改变必须通过纯函数完成)</li> </ul> <h3>(1) 自己实现Redux</h3> <p>这个部分,不使用react,直接使用原生的html/js来写一个简易的的redux</p> <p><strong>基本的状态管理及数据渲染:</strong></p> <pre><code class="prism language-html"><span class="token doctype"><!DOCTYPE html></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>UTF-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1.0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>X-UA-Compatible<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ie=edge<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Redux principle 01<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>redux principle<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>counter<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>btn<span class="token punctuation">"</span></span> <span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>dispatch({type: <span class="token punctuation">'</span>COUNT_DECREMENT<span class="token punctuation">'</span>, number: 10})<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>-<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>count<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>count<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>btn<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>add<span class="token punctuation">"</span></span> <span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>dispatch({type: <span class="token punctuation">'</span>COUNT_INCREMENT<span class="token punctuation">'</span>, number: 10})<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>+<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script language-javascript"> <span class="token comment">// 定义一个计数器的状态</span> <span class="token keyword">const</span> countState <span class="token operator">=</span> <span class="token punctuation">{ </span> count<span class="token punctuation">:</span> <span class="token number">10</span> <span class="token punctuation">}</span> <span class="token comment">// 定一个方法叫changeState,用于处理state的数据,每次都返回一个新的状态</span> <span class="token keyword">const</span> <span class="token function-variable function">changeState</span> <span class="token operator">=</span> <span class="token punctuation">(</span>action<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">switch</span><span class="token punctuation">(</span>action<span class="token punctuation">.</span>type<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token comment">// 处理减</span> <span class="token keyword">case</span> <span class="token string">'COUNT_DECREMENT'</span><span class="token punctuation">:</span> countState<span class="token punctuation">.</span>count <span class="token operator">-=</span> action<span class="token punctuation">.</span>number <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token comment">// 处理加 </span> <span class="token keyword">case</span> <span class="token string">'COUNT_INCREMENT'</span><span class="token punctuation">:</span> countState<span class="token punctuation">.</span>count <span class="token operator">+=</span> action<span class="token punctuation">.</span>number <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">default</span><span class="token punctuation">:</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// 定义一个方法用于渲染计数器的dom</span> <span class="token keyword">const</span> <span class="token function-variable function">renderCount</span> <span class="token operator">=</span> <span class="token punctuation">(</span>state<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> countDom <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#count'</span><span class="token punctuation">)</span> countDom<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> state<span class="token punctuation">.</span>count <span class="token punctuation">}</span> <span class="token comment">// 首次渲染数据</span> <span class="token function">renderCount</span><span class="token punctuation">(</span>countState<span class="token punctuation">)</span> <span class="token comment">// 定义一个dispatch的方法,接收到动作之后,自动调用</span> <span class="token keyword">const</span> <span class="token function-variable function">dispatch</span> <span class="token operator">=</span> <span class="token punctuation">(</span>action<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token function">changeState</span><span class="token punctuation">(</span>action<span class="token punctuation">)</span> <span class="token function">renderCount</span><span class="token punctuation">(</span>countState<span class="token punctuation">)</span> <span class="token punctuation">}</span> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span> </code></pre> <p><strong>创建createStore方法</strong></p> <pre><code class="prism language-html"><span class="token doctype"><!DOCTYPE html></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>UTF-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1.0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>X-UA-Compatible<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ie=edge<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Redux principle 02<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>redux principle<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>counter<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>btn<span class="token punctuation">"</span></span> <span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>store.dispatch({type: <span class="token punctuation">'</span>COUNT_DECREMENT<span class="token punctuation">'</span>, number: 10})<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>-<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>count<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>count<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>btn<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>add<span class="token punctuation">"</span></span> <span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>store.dispatch({type: <span class="token punctuation">'</span>COUNT_INCREMENT<span class="token punctuation">'</span>, number: 10})<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>+<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script language-javascript"> <span class="token comment">// 定义一个方法,用于集中管理state和dispatch</span> <span class="token keyword">const</span> <span class="token function-variable function">createStore</span> <span class="token operator">=</span> <span class="token punctuation">(</span>state<span class="token punctuation">,</span> changeState<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token comment">// getState用于获取状态</span> <span class="token keyword">const</span> <span class="token function-variable function">getState</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> state <span class="token comment">// 定义一个监听器,用于管理一些方法</span> <span class="token keyword">const</span> listeners <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token keyword">const</span> <span class="token function-variable function">subscribe</span> <span class="token operator">=</span> <span class="token punctuation">(</span>listener<span class="token punctuation">)</span> <span class="token operator">=></span> listeners<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>listener<span class="token punctuation">)</span> <span class="token comment">// 定义一个dispatch方法,让每次有action传入的时候返回render执行之后的结果</span> <span class="token keyword">const</span> <span class="token function-variable function">dispatch</span> <span class="token operator">=</span> <span class="token punctuation">(</span>action<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token comment">// 调用changeState来处理数据</span> <span class="token function">changeState</span><span class="token punctuation">(</span>state<span class="token punctuation">,</span> action<span class="token punctuation">)</span> <span class="token comment">// 让监听器里的所以方法运行</span> listeners<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>listener <span class="token operator">=></span> <span class="token function">listener</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">{ </span> getState<span class="token punctuation">,</span> dispatch<span class="token punctuation">,</span> subscribe <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// 定义一个计数器的状态</span> <span class="token keyword">const</span> countState <span class="token operator">=</span> <span class="token punctuation">{ </span> count<span class="token punctuation">:</span> <span class="token number">10</span> <span class="token punctuation">}</span> <span class="token comment">// 定一个方法叫changeState,用于处理state的数据,每次都返回一个新的状态</span> <span class="token keyword">const</span> <span class="token function-variable function">changeState</span> <span class="token operator">=</span> <span class="token punctuation">(</span>state<span class="token punctuation">,</span> action<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">switch</span><span class="token punctuation">(</span>action<span class="token punctuation">.</span>type<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token comment">// 处理减</span> <span class="token keyword">case</span> <span class="token string">'COUNT_DECREMENT'</span><span class="token punctuation">:</span> state<span class="token punctuation">.</span>count <span class="token operator">-=</span> action<span class="token punctuation">.</span>number <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token comment">// 处理加 </span> <span class="token keyword">case</span> <span class="token string">'COUNT_INCREMENT'</span><span class="token punctuation">:</span> state<span class="token punctuation">.</span>count <span class="token operator">+=</span> action<span class="token punctuation">.</span>number <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">default</span><span class="token punctuation">:</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// 创建一个store</span> <span class="token keyword">const</span> store <span class="token operator">=</span> <span class="token function">createStore</span><span class="token punctuation">(</span>countState<span class="token punctuation">,</span> changeState<span class="token punctuation">)</span> <span class="token comment">// 定义一个方法用于渲染计数器的dom</span> <span class="token keyword">const</span> <span class="token function-variable function">renderCount</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> countDom <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#count'</span><span class="token punctuation">)</span> countDom<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> store<span class="token punctuation">.</span><span class="token function">getState</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>count <span class="token punctuation">}</span> <span class="token comment">// 初次渲染数据</span> <span class="token function">renderCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 监听,只要有dispatch,这个方法就会自动运行</span> store<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>renderCount<span class="token punctuation">)</span> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span> </code></pre> <p><strong>让changeState方法变为一个纯函数</strong></p> <pre><code class="prism language-html"><span class="token doctype"><!DOCTYPE html></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>UTF-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1.0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>X-UA-Compatible<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ie=edge<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Redux principle 03<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>redux principle<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>counter<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>btn<span class="token punctuation">"</span></span> <span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>store.dispatch({type: <span class="token punctuation">'</span>COUNT_DECREMENT<span class="token punctuation">'</span>, number: 10})<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>-<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>count<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>count<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>btn<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>add<span class="token punctuation">"</span></span> <span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>store.dispatch({type: <span class="token punctuation">'</span>COUNT_INCREMENT<span class="token punctuation">'</span>, number: 10})<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>+<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script language-javascript"> <span class="token comment">// 定义一个方法,用于集中管理state和dispatch</span> <span class="token keyword">const</span> <span class="token function-variable function">createStore</span> <span class="token operator">=</span> <span class="token punctuation">(</span>state<span class="token punctuation">,</span> changeState<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token comment">// getState用于获取状态</span> <span class="token keyword">const</span> <span class="token function-variable function">getState</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> state <span class="token comment">// 定义一个监听器,用于管理一些方法</span> <span class="token keyword">const</span> listeners <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token keyword">const</span> <span class="token function-variable function">subscribe</span> <span class="token operator">=</span> <span class="token punctuation">(</span>listener<span class="token punctuation">)</span> <span class="token operator">=></span> listeners<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>listener<span class="token punctuation">)</span> <span class="token comment">// 定义一个dispatch方法,让每次有action传入的时候返回render执行之后的结果</span> <span class="token keyword">const</span> <span class="token function-variable function">dispatch</span> <span class="token operator">=</span> <span class="token punctuation">(</span>action<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token comment">// 调用changeState来处理数据</span> state <span class="token operator">=</span> <span class="token function">changeState</span><span class="token punctuation">(</span>state<span class="token punctuation">,</span> action<span class="token punctuation">)</span> <span class="token comment">// 让监听器里的所有方法运行</span> listeners<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>listener <span class="token operator">=></span> <span class="token function">listener</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">{ </span> getState<span class="token punctuation">,</span> dispatch<span class="token punctuation">,</span> subscribe <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// 定义一个计数器的状态</span> <span class="token keyword">const</span> countState <span class="token operator">=</span> <span class="token punctuation">{ </span> count<span class="token punctuation">:</span> <span class="token number">10</span> <span class="token punctuation">}</span> <span class="token comment">// 定一个方法叫changeState,用于处理state的数据,每次都返回一个新的状态</span> <span class="token keyword">const</span> <span class="token function-variable function">changeState</span> <span class="token operator">=</span> <span class="token punctuation">(</span>state<span class="token punctuation">,</span> action<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">switch</span><span class="token punctuation">(</span>action<span class="token punctuation">.</span>type<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token comment">// 处理减</span> <span class="token keyword">case</span> <span class="token string">'COUNT_DECREMENT'</span><span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token punctuation">{ </span> <span class="token operator">...</span>state<span class="token punctuation">,</span> count<span class="token punctuation">:</span> state<span class="token punctuation">.</span>count <span class="token operator">-</span> action<span class="token punctuation">.</span>number <span class="token punctuation">}</span> <span class="token comment">// 处理加 </span> <span class="token keyword">case</span> <span class="token string">'COUNT_INCREMENT'</span><span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token punctuation">{ </span> <span class="token operator">...</span>state<span class="token punctuation">,</span> count<span class="token punctuation">:</span> state<span class="token punctuation">.</span>count <span class="token operator">+</span> action<span class="token punctuation">.</span>number <span class="token punctuation">}</span> <span class="token keyword">default</span><span class="token punctuation">:</span> <span class="token keyword">return</span> state <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// 创建一个store</span> <span class="token keyword">const</span> store <span class="token operator">=</span> <span class="token function">createStore</span><span class="token punctuation">(</span>countState<span class="token punctuation">,</span> changeState<span class="token punctuation">)</span> <span class="token comment">// 定义一个方法用于渲染计数器的dom</span> <span class="token keyword">const</span> <span class="token function-variable function">renderCount</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> countDom <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#count'</span><span class="token punctuation">)</span> countDom<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> store<span class="token punctuation">.</span><span class="token function">getState</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>count <span class="token punctuation">}</span> <span class="token comment">// 初次渲染数据</span> <span class="token function">renderCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 监听,只要有dispatch,这个方法就会自动运行</span> store<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>renderCount<span class="token punctuation">)</span> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span> </code></pre> <p><strong>合并state和changeState(最终版)</strong></p> <pre><code class="prism language-html"><span class="token doctype"><!DOCTYPE html></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>UTF-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1.0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>X-UA-Compatible<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ie=edge<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Redux principle 04<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>redux principle<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>counter<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>btn<span class="token punctuation">"</span></span> <span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>store.dispatch({type: <span class="token punctuation">'</span>COUNT_DECREMENT<span class="token punctuation">'</span>, number: 10})<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>-<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>count<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>count<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>btn<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>add<span class="token punctuation">"</span></span> <span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>store.dispatch({type: <span class="token punctuation">'</span>COUNT_INCREMENT<span class="token punctuation">'</span>, number: 10})<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>+<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script language-javascript"> <span class="token comment">// 定义一个方法,用于集中管理state和dispatch, changeState改名了,专业的叫法是reducer</span> <span class="token keyword">const</span> <span class="token function-variable function">createStore</span> <span class="token operator">=</span> <span class="token punctuation">(</span>reducer<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token comment">// 定义一个初始的state</span> <span class="token keyword">let</span> state <span class="token operator">=</span> <span class="token keyword">null</span> <span class="token comment">// getState用于获取状态</span> <span class="token keyword">const</span> <span class="token function-variable function">getState</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> state <span class="token comment">// 定义一个监听器,用于管理一些方法</span> <span class="token keyword">const</span> listeners <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token keyword">const</span> <span class="token function-variable function">subscribe</span> <span class="token operator">=</span> <span class="token punctuation">(</span>listener<span class="token punctuation">)</span> <span class="token operator">=></span> listeners<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>listener<span class="token punctuation">)</span> <span class="token comment">// 定义一个dispatch方法,让每次有action传入的时候返回reducer执行之后的结果</span> <span class="token keyword">const</span> <span class="token function-variable function">dispatch</span> <span class="token operator">=</span> <span class="token punctuation">(</span>action<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token comment">// 调用reducer来处理数据</span> state <span class="token operator">=</span> <span class="token function">reducer</span><span class="token punctuation">(</span>state<span class="token punctuation">,</span> action<span class="token punctuation">)</span> <span class="token comment">// 让监听器里的所有方法运行</span> listeners<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>listener <span class="token operator">=></span> <span class="token function">listener</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">// 初始化state</span> <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{ </span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">{ </span> getState<span class="token punctuation">,</span> dispatch<span class="token punctuation">,</span> subscribe <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// 定义一个计数器的状态</span> <span class="token keyword">const</span> countState <span class="token operator">=</span> <span class="token punctuation">{ </span> count<span class="token punctuation">:</span> <span class="token number">10</span> <span class="token punctuation">}</span> <span class="token comment">// 定一个方法叫changeState,用于处理state的数据,每次都返回一个新的状态</span> <span class="token keyword">const</span> <span class="token function-variable function">changeState</span> <span class="token operator">=</span> <span class="token punctuation">(</span>state<span class="token punctuation">,</span> action<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token comment">// 如果state是null, 就返回countState</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>state<span class="token punctuation">)</span> <span class="token keyword">return</span> countState <span class="token keyword">switch</span><span class="token punctuation">(</span>action<span class="token punctuation">.</span>type<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token comment">// 处理减</span> <span class="token keyword">case</span> <span class="token string">'COUNT_DECREMENT'</span><span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token punctuation">{ </span> <span class="token operator">...</span>state<span class="token punctuation">,</span> count<span class="token punctuation">:</span> state<span class="token punctuation">.</span>count <span class="token operator">-</span> action<span class="token punctuation">.</span>number <span class="token punctuation">}</span> <span class="token comment">// 处理加 </span> <span class="token keyword">case</span> <span class="token string">'COUNT_INCREMENT'</span><span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token punctuation">{ </span> <span class="token operator">...</span>state<span class="token punctuation">,</span> count<span class="token punctuation">:</span> state<span class="token punctuation">.</span>count <span class="token operator">+</span> action<span class="token punctuation">.</span>number <span class="token punctuation">}</span> <span class="token keyword">default</span><span class="token punctuation">:</span> <span class="token keyword">return</span> state <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// 创建一个store</span> <span class="token keyword">const</span> store <span class="token operator">=</span> <span class="token function">createStore</span><span class="token punctuation">(</span>changeState<span class="token punctuation">)</span> <span class="token comment">// 定义一个方法用于渲染计数器的dom</span> <span class="token keyword">const</span> <span class="token function-variable function">renderCount</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> countDom <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#count'</span><span class="token punctuation">)</span> countDom<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> store<span class="token punctuation">.</span><span class="token function">getState</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>count <span class="token punctuation">}</span> <span class="token comment">// 初次渲染数据</span> <span class="token function">renderCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 监听,只要有dispatch,renderCount就会自动运行</span> store<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>renderCount<span class="token punctuation">)</span> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span> </code></pre> <h3>(2) 使用Redux框架</h3> <p><strong>Redux的流程:</strong></p> <p><a href="http://img.e-com-net.com/image/info8/5745e54664544a65813394cf0abcc1de.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/5745e54664544a65813394cf0abcc1de.jpg" alt="2021react复习_第4张图片" width="650" height="253" style="border:1px solid black;"></a></p> <ul> <li>store通过reducer创建了初始状态</li> <li>view通过store.getState()获取到了store中保存的state挂载在了自己的状态上</li> <li>用户产生了操作,调用了actions 的方法</li> <li>actions的方法被调用,创建了带有标示性信息的action</li> <li>actions将action通过调用store.dispatch方法发送到了reducer中</li> <li>reducer接收到action并根据标识信息判断之后返回了新的state</li> <li>store的state被reducer更改为新state的时候,store.subscribe方法里的回调函数会执行,此时就可以通知view去重新获取state</li> </ul> <p><strong>Reducer必须是一个纯函数:</strong></p> <p>Reducer 函数最重要的特征是,它是一个纯函数。也就是说,只要是同样的输入,必定得到同样的输出。Reducer不是只有Redux里才有,之前学的数组方法<code>reduce</code>, 它的第一个参数就是一个reducer</p> <p>纯函数是函数式编程的概念,必须遵守以下一些约束。</p> <ul> <li>不得改写参数</li> <li>不能调用系统 I/O 的API</li> <li>不能调用Date.now()或者Math.random()等不纯的方法,因为每次会得到不一样的结果</li> </ul> <p>由于 Reducer 是纯函数,就可以保证同样的State,必定得到同样的 View。但也正因为这一点,Reducer 函数里面不能改变 State,必须返回一个全新的对象,请参考下面的写法。</p> <pre><code class="prism language-js"><span class="token comment">// State 是一个对象</span> <span class="token keyword">function</span> <span class="token function">reducer</span><span class="token punctuation">(</span>state <span class="token operator">=</span> defaultState<span class="token punctuation">,</span> action<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> Object<span class="token punctuation">.</span><span class="token function">assign</span><span class="token punctuation">(</span><span class="token punctuation">{ </span><span class="token punctuation">}</span><span class="token punctuation">,</span> state<span class="token punctuation">,</span> <span class="token punctuation">{ </span> thingToChange <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 或者</span> <span class="token keyword">return</span> <span class="token punctuation">{ </span> <span class="token operator">...</span>state<span class="token punctuation">,</span> <span class="token operator">...</span>newState <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// State 是一个数组</span> <span class="token keyword">function</span> <span class="token function">reducer</span><span class="token punctuation">(</span>state <span class="token operator">=</span> defaultState<span class="token punctuation">,</span> action<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token operator">...</span>state<span class="token punctuation">,</span> newItem<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>最好把 State 对象设成只读。要得到新的 State,唯一办法就是生成一个新对象。这样的好处是,任何时候,与某个 View 对应的 State 总是一个不变(immutable)的对象。</p> <p>我们可以通过在createStore中传入第二个参数来设置默认的state,但是这种形式只适合于只有一个reducer的时候。</p> <p><strong>划分reducer</strong>:</p> <p>因为一个应用中只能有一个大的state,这样的话reducer中的代码将会特别特别的多,那么就可以使用combineReducers方法将已经分开的reducer合并到一起</p> <blockquote> <p>注意:</p> <ol> <li>分离reducer的时候,每一个reducer维护的状态都应该不同</li> <li>通过store.getState获取到的数据也是会按照reducers去划分的</li> <li>划分多个reducer的时候,默认状态只能创建在reducer中,因为划分reducer的目的,就是为了让每一个reducer都去独立管理一部分状态</li> </ol> </blockquote> <p><em>最开始一般基于计数器的例子讲解redux的基本使用即可</em>。</p> <p>关于action/reducer/store的更多概念,请查看官网</p> <p><strong>Redux异步</strong></p> <p>通常情况下,action只是一个对象,不能包含异步操作,这导致了很多创建action的逻辑只能写在组件中,代码量较多也不便于复用,同时对该部分代码测试的时候也比较困难,组件的业务逻辑也不清晰,使用中间件了之后,可以通过actionCreator异步编写action,这样代码就会拆分到actionCreator中,可维护性大大提高,可以方便于测试、复用,同时actionCreator还集成了异步操作中不同的action派发机制,减少编码过程中的代码量</p> <p>常见的异步库:</p> <ul> <li>Redux-thunk</li> <li>Redux-saga</li> <li>Redux-effects</li> <li>Redux-side-effects</li> <li>Redux-loop</li> <li>Redux-observable</li> <li>…</li> </ul> <p>基于Promise的异步库:</p> <ul> <li>Redux-promise</li> <li>Redux-promises</li> <li>Redux-simple-promise</li> <li>Redux-promise-middleware</li> <li>…</li> </ul> <h3>(3) 容器组件(Smart/Container Components)和展示组件(Dumb/Presentational Components)</h3> <table> <thead> <tr> <th></th> <th>展示组件</th> <th>容器组件</th> </tr> </thead> <tbody> <tr> <td>作用</td> <td>描述如何展现(骨架、样式)</td> <td>描述如何运行(数据获取、状态更新)</td> </tr> <tr> <td>直接使用 Redux</td> <td>否</td> <td>是</td> </tr> <tr> <td>数据来源</td> <td>props</td> <td>监听 Redux state</td> </tr> <tr> <td>数据修改</td> <td>从 props 调用回调函数</td> <td>向 Redux 派发 actions</td> </tr> <tr> <td>调用方式</td> <td>手动</td> <td>通常由 React Redux 生成</td> </tr> </tbody> </table> <h3>(4) 使用react-redux</h3> <p>可以先结合<code>context</code>来手动连接react和redux。</p> <p>react-redux提供两个核心的api:</p> <ul> <li> <p>Provider: 提供store</p> </li> <li> <p>connect: 用于连接容器组件和展示组件</p> <ul> <li> <p>Provider</p> <p>根据单一store原则 ,一般只会出现在整个应用程序的最顶层。</p> </li> <li> <p>connect</p> <p>语法格式为</p> <p><code>connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?)(component)</code></p> <p>一般来说只会用到前面两个,它的作用是:</p> <ul> <li>把<code>store.getState()</code>的状态转化为展示组件的<code>props</code></li> <li>把<code>actionCreators</code>转化为展示组件<code>props</code>上的方法</li> </ul> </li> </ul> </li> </ul> <blockquote> <p>特别强调:</p> <p>官网上的第二个参数为mapDispatchToProps, 实际上就是actionCreators</p> </blockquote> <p>只要上层中有<code>Provider</code>组件并且提供了<code>store</code>, 那么,子孙级别的任何组件,要想使用<code>store</code>里的状态,都可以通过<code>connect</code>方法进行连接。如果只是想连接<code>actionCreators</code>,可以第一个参数传递为<code>null</code></p> <h1>十六、React Router</h1> <p>React Router现在的版本是5, 于2019年3月21日搞笑的发布,搞笑的官网链接, 本来是要发布4.4的版本的,结果成了5。从4开始,使用方式相对于之前版本的思想有所不同。之前版本的思想是传统的思想:<strong>路由应该统一在一处渲染</strong>, Router 4之后是这样的思想:<strong>一切皆组件</strong></p> <p>React Router包含了四个包:</p> <table> <thead> <tr> <th>包名</th> <th>Description</th> </tr> </thead> <tbody> <tr> <td><code>react-router</code></td> <td>React Router核心api</td> </tr> <tr> <td><code>react-router-dom</code></td> <td>React Router的DOM绑定,在浏览器中运行不需要额外安装<code>react-router</code></td> </tr> <tr> <td><code>react-router-native</code></td> <td>React Native 中使用,而实际的应用中,其实不会使用这个。</td> </tr> <tr> <td><code>react-router-config</code></td> <td>静态路由的配置</td> </tr> </tbody> </table> <p>主要使用<code>react-router-dom</code></p> <h2>1、使用方式</h2> <p>正常情况下,直接按照官网的demo就理解 路由的使用方式,有几个点需要特别的强调:</p> <p>一个很好的文档</p> <h3>Route组件的exact属性</h3> <p><code>exact</code>属性标识是否为严格匹配, 为<code>true</code>是表示严格匹配,为<code>false</code>时为正常匹配。</p> <h3>Route组件的render属性而不是component属性</h3> <p>怎么在渲染组件的时候,对组件传递属性呢?使用<code>component</code>的方式是不能直接在组件上添加属性的。所以,React Router的<code>Route</code>组件提供了另一种渲染组件的方式 <code>render</code>, 这个常用于页面组件级别的权限管理。</p> <p>一个最基本的判别,component组件可以直接传组件也可以函数,render和children必须传函数渲染然后加一个属性props传下去,render和children的区别,render只有路由匹配的时候才渲染,而children就直接拍在上面</p> <p>children的使用是不会自动注销的,但是不是自己匹配到的时候会也显示,和普通的组件会加一个props属性来显示自己的所在位置,因为被route包裹了,而且如果路由时匹配的话,就会自动在match上有属性,否则是null</p> <p><strong>render</strong></p> <p>render属性能使你便捷的渲染内联组件或是嵌套组件,你可以给这个属性传入一个函数,当路由的路径匹配时调用。同时,render属性也会接受所有由route传入的所有参数。</p> <pre><code class="prism language-js"><span class="token comment">//内联方式</span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"path"</span> render<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator"><</span>div<span class="token operator">></span>这是内联组件写法<span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token comment">//嵌套组合方式</span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"path"</span> render<span class="token operator">=</span><span class="token punctuation">{ </span> props <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>ParentComp<span class="token operator">></span> <span class="token operator"><</span>Comp <span class="token punctuation">{ </span><span class="token operator">...</span>props<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>ParentComp<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token operator">/</span><span class="token operator">></span> </code></pre> <p><strong>component</strong></p> <p>当你使用component属性时,router会通过你赋给该属性的值,使用React.createElement方法去创建一个新的React元素,这意味着如果你给component属性赋的值是一个内联函数,那他每次渲染都会创建一个新的组件,这会导致每次渲染都会伴随新组件的挂载和旧组件的卸载,而不是只是对已存在组件的更新操作。<br> 所以当你要使用内联函数进行组件渲染时,使用render或children属性会更合适些。</p> <pre><code class="prism language-js"><span class="token keyword">const</span> <span class="token function-variable function">Comp</span> <span class="token operator">=</span> props <span class="token operator">=></span> <span class="token operator"><</span>div<span class="token operator">></span><span class="token punctuation">{ </span>props<span class="token punctuation">.</span>match<span class="token punctuation">.</span>params<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"path"</span> component<span class="token operator">=</span><span class="token punctuation">{ </span>Comp<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> </code></pre> <p><strong>children</strong></p> <p>children属性是这三个属性中比较特殊的一个,它的值为一个函数,当Route有children属性时,不管当前的路径是否与Route匹配,该函数都会执行,同时,children属性也会接受所有由route传入的所有参数。</p> <pre><code class="prism language-js"><span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"path"</span> children<span class="token operator">=</span><span class="token punctuation">{ </span> props <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token punctuation">{ </span>props<span class="token punctuation">.</span>match<span class="token operator">?</span> <span class="token string">"active"</span><span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Link to<span class="token operator">=</span><span class="token string">"path"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token operator">/</span><span class="token operator">></span> </code></pre> <p><strong>直接当子组件也可以</strong>,不过用的比较少</p> <h3>路由的参数传递与获取</h3> <p>动态路由是用/:id来区别于固定的/id,可以先console.log(this)打印,在props属性下会找到match,这个里面是放属性的,其实根节点的route组件就是将这些属性挂载在了props上面,这样可以方便查找(可能理解有误)</p> <p>match下有两个参数,一个是url用来获取当前自己的路由是什么,一个是params来获取动态路由的参数用的</p> <p>以上是class组件和初学的认知,现在总结总共有三种方法:</p> <ol> <li>用/:id的动态路由,useParams的钩子来获取,或者props下的match来拿</li> <li>在route或redirect的to里加参数,useLocation的钩子来获取,或者props下的match来拿</li> <li>用query的方法?id直接在路由上查询,可以用loaction来查看,但可以用浏览器的对象URLSearchParams来直接获取<code>URLSearchParams(useLocation().search).get('参数')</code></li> </ol> <h3>Switch组件</h3> <p>总是渲染第一个匹配到的组件,本质是分支的意思switch的一篇很好的文章</p> <p>而且很重要的是加了switch组件后children属性直接不会显示,本质是switch只会渲染其匹配到的,是非兼容性的组件,而不加的话route是兼容性的组件,所以children属性的route会被渲染出来</p> <p>因为上面的这个原因,所以必须有404的页面里或者login页面里要用switch来渲染</p> <h3>处理404与默认页</h3> <p>用redirect组件来进行操作</p> <pre><code class="prism language-js"><span class="token operator"><</span>Switch<span class="token operator">></span> <span class="token operator"><</span>Route to <span class="token operator">=</span> <span class="token string">'/home'</span> component<span class="token operator">=</span><span class="token punctuation">{ </span>home<span class="token punctuation">}</span> <span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>Route<span class="token operator">></span> <span class="token operator"><</span>Route to <span class="token operator">=</span> <span class="token string">'/topic'</span> component<span class="token operator">=</span><span class="token punctuation">{ </span>topic<span class="token punctuation">}</span> <span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>Route<span class="token operator">></span> <span class="token operator"><</span>Route to <span class="token operator">=</span> <span class="token string">'/about'</span> component<span class="token operator">=</span><span class="token punctuation">{ </span>about<span class="token punctuation">}</span> <span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>Route<span class="token operator">></span> <span class="token operator"><</span>Redirect <span class="token keyword">from</span> <span class="token operator">=</span> <span class="token string">'/'</span> to <span class="token operator">=</span> <span class="token string">'/about'</span> <span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>Redirct<span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"*"</span> <span class="token operator">></span> <span class="token operator"><</span>page404<span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>page404<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Route<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Switch<span class="token operator">></span> </code></pre> <h3>withRoute高阶组件的使用</h3> <p>高阶组件中的<code>withRouter</code>, 作用是将一个组件包裹进<code>Route</code>里面, 然后<code>react-router</code>的三个对象<code>history, location, match</code>就会被放进这个组件的<code>props</code>属性中.</p> <pre><code class="prism language-js"><span class="token comment">// withRouter实现原理: </span> <span class="token comment">// 将组件包裹进 Route, 然后返回</span> <span class="token comment">// const withRouter = () => { </span> <span class="token comment">// return () => { </span> <span class="token comment">// return <Route component={Nav} /></span> <span class="token comment">// }</span> <span class="token comment">// }</span> <span class="token comment">// 这里是简化版</span> <span class="token keyword">const</span> <span class="token function-variable function">withRouter</span> <span class="token operator">=</span> <span class="token punctuation">(</span> Component <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator"><</span>Route component<span class="token operator">=</span><span class="token punctuation">{ </span> Component <span class="token punctuation">}</span><span class="token operator">/</span><span class="token operator">></span> </code></pre> <p>上面是实现的原理, <code>react-router-dom</code> 里面是有这个组件的, 直接引入使用就可以了</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">import</span> <span class="token string">'./nav.css'</span> <span class="token keyword">import</span> <span class="token punctuation">{ </span> NavLink<span class="token punctuation">,</span> withRouter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-router-dom"</span> <span class="token keyword">class</span> <span class="token class-name">Nav</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span><span class="token punctuation">{ </span> <span class="token function-variable function">handleClick</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token comment">// Route 的 三个对象将会被放进来, 对象里面的方法可以被调用</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function-variable function">click</span> <span class="token operator">=</span> <span class="token punctuation">(</span>path<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">let</span> history <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>history <span class="token keyword">return</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{ </span> history<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token operator">+</span>path<span class="token punctuation">)</span> <span class="token comment">//通过路由导航做的,浏览器会记录的,不会出现浏览前进后退的错误</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token string">'nav'</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>span className<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token string">'logo'</span><span class="token punctuation">}</span> onClick<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>handleClick<span class="token punctuation">}</span><span class="token operator">></span>掘土社区<span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span> <span class="token operator"><</span>li<span class="token operator">></span><span class="token operator"><</span>NavLink to<span class="token operator">=</span><span class="token string">"/"</span> exact<span class="token operator">></span>首页<span class="token operator"><</span><span class="token operator">/</span>NavLink<span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>li<span class="token operator">></span> <span class="token operator"><</span>li<span class="token operator">></span><span class="token operator"><</span>NavLink to<span class="token operator">=</span><span class="token string">"/activities"</span><span class="token operator">></span>动态<span class="token operator"><</span><span class="token operator">/</span>NavLink<span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>li<span class="token operator">></span> <span class="token operator"><</span>li<span class="token operator">></span><span class="token operator"><</span>NavLink to<span class="token operator">=</span><span class="token string">"/topic"</span><span class="token operator">></span>话题<span class="token operator"><</span><span class="token operator">/</span>NavLink<span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>li<span class="token operator">></span> <span class="token operator"><</span>li<span class="token operator">></span><span class="token operator"><</span>NavLink to<span class="token operator">=</span><span class="token string">"/login"</span><span class="token operator">></span>登录<span class="token operator"><</span><span class="token operator">/</span>NavLink<span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>li<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// 导出的是 withRouter(Nav) 函数执行</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token function">withRouter</span><span class="token punctuation">(</span>Nav<span class="token punctuation">)</span> </code></pre> <p>所以<code>withRouter</code>的作用就是, 如果我们某个东西不是一个<code>Router</code>, 但是我们要依靠它去跳转一个页面, 比如点击页面的<code>logo</code>, 返回首页, 这时候就可以使用<code>withRouter</code>来做.<br> 在这个例子中, 我将<code>span</code>使用<code>withRouter</code>作为一个可点击跳转的<code>Link</code></p> <h3>管理一个项目路由的方法</h3> <p>很初级的在类里面定义方式:</p> <pre><code class="prism language-js">state <span class="token operator">=</span> <span class="token punctuation">{ </span> list<span class="token punctuation">:</span><span class="token punctuation">[</span> <span class="token punctuation">{ </span> id<span class="token punctuation">:</span><span class="token number">001</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span><span class="token string">'one'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{ </span> id<span class="token punctuation">:</span><span class="token number">002</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span><span class="token string">'two'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{ </span> id<span class="token punctuation">:</span><span class="token number">003</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span><span class="token string">'three'</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{ </span> <span class="token keyword">return</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{ </span> <span class="token operator"><</span><span class="token operator">></span> <span class="token punctuation">{ </span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>list<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>value <span class="token operator">=></span> <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token operator"><</span>li key<span class="token operator">=</span><span class="token punctuation">{ </span>value<span class="token punctuation">.</span>id<span class="token punctuation">}</span> <span class="token operator">></span><span class="token punctuation">{ </span>value<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>li<span class="token operator">></span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <p>官方的案例可以参考:</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{ </span> BrowserRouter <span class="token keyword">as</span> Router<span class="token punctuation">,</span> Switch<span class="token punctuation">,</span> Route<span class="token punctuation">,</span> Link <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-router-dom"</span><span class="token punctuation">;</span> <span class="token comment">// Each logical "route" has two components, one for</span> <span class="token comment">// the sidebar and one for the main area. We want to</span> <span class="token comment">// render both of them in different places when the</span> <span class="token comment">// path matches the current URL.</span> <span class="token comment">// We are going to use this route config in 2</span> <span class="token comment">// spots: once for the sidebar and once in the main</span> <span class="token comment">// content section. All routes are in the same</span> <span class="token comment">// order they would appear in a <Switch>.</span> <span class="token keyword">const</span> routes <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">{ </span> path<span class="token punctuation">:</span> <span class="token string">"/"</span><span class="token punctuation">,</span> exact<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> sidebar<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator"><</span>div<span class="token operator">></span>home<span class="token operator">!</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">,</span> main<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator"><</span>h2<span class="token operator">></span>Home<span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{ </span> path<span class="token punctuation">:</span> <span class="token string">"/bubblegum"</span><span class="token punctuation">,</span> sidebar<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator"><</span>div<span class="token operator">></span>bubblegum<span class="token operator">!</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">,</span> main<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator"><</span>h2<span class="token operator">></span>Bubblegum<span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{ </span> path<span class="token punctuation">:</span> <span class="token string">"/shoelaces"</span><span class="token punctuation">,</span> sidebar<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator"><</span>div<span class="token operator">></span>shoelaces<span class="token operator">!</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">,</span> main<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator"><</span>h2<span class="token operator">></span>Shoelaces<span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">SidebarExample</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Router<span class="token operator">></span> <span class="token operator"><</span>div style<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">{ </span> display<span class="token punctuation">:</span> <span class="token string">"flex"</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>div style<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">{ </span> padding<span class="token punctuation">:</span> <span class="token string">"10px"</span><span class="token punctuation">,</span> width<span class="token punctuation">:</span> <span class="token string">"40%"</span><span class="token punctuation">,</span> background<span class="token punctuation">:</span> <span class="token string">"#f0f0f0"</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">></span> <span class="token operator"><</span>ul style<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">{ </span> listStyleType<span class="token punctuation">:</span> <span class="token string">"none"</span><span class="token punctuation">,</span> padding<span class="token punctuation">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token punctuation">{ </span>routes<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">{ </span>path<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=></span><span class="token punctuation">{ </span> <span class="token keyword">return</span><span class="token operator"><</span>li key<span class="token operator">=</span><span class="token punctuation">{ </span>path<span class="token punctuation">}</span><span class="token operator">></span><span class="token operator"><</span>Link to<span class="token operator">=</span><span class="token punctuation">{ </span>path<span class="token punctuation">}</span><span class="token operator">></span><span class="token punctuation">{ </span>path<span class="token operator">===</span><span class="token string">'/'</span> <span class="token operator">?</span><span class="token string">'home'</span><span class="token punctuation">:</span>path<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>Link<span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>li<span class="token operator">></span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>ul<span class="token operator">></span> <span class="token operator"><</span>Switch<span class="token operator">></span> <span class="token punctuation">{ </span>routes<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>route<span class="token punctuation">,</span> index<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token comment">// You can render a <Route> in as many places</span> <span class="token comment">// as you want in your app. It will render along</span> <span class="token comment">// with any other <Route>s that also match the URL.</span> <span class="token comment">// So, a sidebar or breadcrumbs or anything else</span> <span class="token comment">// that requires you to render multiple things</span> <span class="token comment">// in multiple places at the same URL is nothing</span> <span class="token comment">// more than multiple <Route>s.</span> <span class="token operator"><</span>Route key<span class="token operator">=</span><span class="token punctuation">{ </span>index<span class="token punctuation">}</span> path<span class="token operator">=</span><span class="token punctuation">{ </span>route<span class="token punctuation">.</span>path<span class="token punctuation">}</span> exact<span class="token operator">=</span><span class="token punctuation">{ </span>route<span class="token punctuation">.</span>exact<span class="token punctuation">}</span> children<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token operator"><</span>route<span class="token punctuation">.</span>sidebar <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>Switch<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span>div style<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">{ </span> flex<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> padding<span class="token punctuation">:</span> <span class="token string">"10px"</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Switch<span class="token operator">></span> <span class="token punctuation">{ </span>routes<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>route<span class="token punctuation">,</span> index<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token comment">// Render more <Route>s with the same paths as</span> <span class="token comment">// above, but different components this time.</span> <span class="token operator"><</span>Route key<span class="token operator">=</span><span class="token punctuation">{ </span>index<span class="token punctuation">}</span> path<span class="token operator">=</span><span class="token punctuation">{ </span>route<span class="token punctuation">.</span>path<span class="token punctuation">}</span> exact<span class="token operator">=</span><span class="token punctuation">{ </span>route<span class="token punctuation">.</span>exact<span class="token punctuation">}</span> children<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token operator"><</span>route<span class="token punctuation">.</span>main <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>Switch<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Router<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>一个更复杂的多层路由配置:</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{ </span> BrowserRouter <span class="token keyword">as</span> Router<span class="token punctuation">,</span> Switch<span class="token punctuation">,</span> Route<span class="token punctuation">,</span> Link <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-router-dom"</span><span class="token punctuation">;</span> <span class="token comment">// Some folks find value in a centralized route config.</span> <span class="token comment">// A route config is just data. React is great at mapping</span> <span class="token comment">// data into components, and <Route> is a component.</span> <span class="token comment">// Our route config is just an array of logical "routes"</span> <span class="token comment">// with `path` and `component` props, ordered the same</span> <span class="token comment">// way you'd do inside a `<Switch>`.</span> <span class="token keyword">const</span> routes <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">{ </span> path<span class="token punctuation">:</span> <span class="token string">"/sandwiches"</span><span class="token punctuation">,</span> component<span class="token punctuation">:</span> Sandwiches <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{ </span> path<span class="token punctuation">:</span> <span class="token string">"/tacos"</span><span class="token punctuation">,</span> component<span class="token punctuation">:</span> Tacos<span class="token punctuation">,</span> routes<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{ </span> path<span class="token punctuation">:</span> <span class="token string">"/tacos/bus"</span><span class="token punctuation">,</span> component<span class="token punctuation">:</span> Bus <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{ </span> path<span class="token punctuation">:</span> <span class="token string">"/tacos/cart"</span><span class="token punctuation">,</span> component<span class="token punctuation">:</span> Cart <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">RouteConfigExample</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Router<span class="token operator">></span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>ul<span class="token operator">></span> <span class="token operator"><</span>li<span class="token operator">></span> <span class="token operator"><</span>Link to<span class="token operator">=</span><span class="token string">"/tacos"</span><span class="token operator">></span>Tacos<span class="token operator"><</span><span class="token operator">/</span>Link<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>li<span class="token operator">></span> <span class="token operator"><</span>li<span class="token operator">></span> <span class="token operator"><</span>Link to<span class="token operator">=</span><span class="token string">"/sandwiches"</span><span class="token operator">></span>Sandwiches<span class="token operator"><</span><span class="token operator">/</span>Link<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>li<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>ul<span class="token operator">></span> <span class="token operator"><</span>Switch<span class="token operator">></span> <span class="token punctuation">{ </span>routes<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>route<span class="token punctuation">,</span> i<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>RouteWithSubRoutes key<span class="token operator">=</span><span class="token punctuation">{ </span>i<span class="token punctuation">}</span> <span class="token punctuation">{ </span><span class="token operator">...</span>route<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>Switch<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Router<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// A special wrapper for <Route> that knows how to</span> <span class="token comment">// handle "sub"-routes by passing them in a `routes`</span> <span class="token comment">// prop to the component it renders.</span> <span class="token keyword">function</span> <span class="token function">RouteWithSubRoutes</span><span class="token punctuation">(</span>route<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token punctuation">{ </span>route<span class="token punctuation">.</span>path<span class="token punctuation">}</span> render<span class="token operator">=</span><span class="token punctuation">{ </span>props <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token comment">// pass the sub-routes down to keep nesting</span> <span class="token operator"><</span>route<span class="token punctuation">.</span>component <span class="token punctuation">{ </span><span class="token operator">...</span>props<span class="token punctuation">}</span> routes<span class="token operator">=</span><span class="token punctuation">{ </span>route<span class="token punctuation">.</span>routes<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">Sandwiches</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token operator"><</span>h2<span class="token operator">></span>Sandwiches<span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">Tacos</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> routes <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>h2<span class="token operator">></span>Tacos<span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span> <span class="token operator"><</span>ul<span class="token operator">></span> <span class="token operator"><</span>li<span class="token operator">></span> <span class="token operator"><</span>Link to<span class="token operator">=</span><span class="token string">"/tacos/bus"</span><span class="token operator">></span>Bus<span class="token operator"><</span><span class="token operator">/</span>Link<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>li<span class="token operator">></span> <span class="token operator"><</span>li<span class="token operator">></span> <span class="token operator"><</span>Link to<span class="token operator">=</span><span class="token string">"/tacos/cart"</span><span class="token operator">></span>Cart<span class="token operator"><</span><span class="token operator">/</span>Link<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>li<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>ul<span class="token operator">></span> <span class="token operator"><</span>Switch<span class="token operator">></span> <span class="token punctuation">{ </span>routes<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>route<span class="token punctuation">,</span> i<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>RouteWithSubRoutes key<span class="token operator">=</span><span class="token punctuation">{ </span>i<span class="token punctuation">}</span> <span class="token punctuation">{ </span><span class="token operator">...</span>route<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>Switch<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">Bus</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token operator"><</span>h3<span class="token operator">></span>Bus<span class="token operator"><</span><span class="token operator">/</span>h3<span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">Cart</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token operator"><</span>h3<span class="token operator">></span>Cart<span class="token operator"><</span><span class="token operator">/</span>h3<span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <h3>递归路由</h3> <p>Recursive Paths,这个操作是真的太6了</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{ </span> BrowserRouter <span class="token keyword">as</span> Router<span class="token punctuation">,</span> Switch<span class="token punctuation">,</span> Route<span class="token punctuation">,</span> Link<span class="token punctuation">,</span> Redirect<span class="token punctuation">,</span> useParams<span class="token punctuation">,</span> useRouteMatch <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-router-dom"</span><span class="token punctuation">;</span> <span class="token comment">// Sometimes you don't know all the possible routes</span> <span class="token comment">// for your application up front; for example, when</span> <span class="token comment">// building a file-system browsing UI or determining</span> <span class="token comment">// URLs dynamically based on data. In these situations,</span> <span class="token comment">// it helps to have a dynamic router that is able</span> <span class="token comment">// to generate routes as needed at runtime.</span> <span class="token comment">//</span> <span class="token comment">// This example lets you drill down into a friends</span> <span class="token comment">// list recursively, viewing each user's friend list</span> <span class="token comment">// along the way. As you drill down, notice each segment</span> <span class="token comment">// being added to the URL. You can copy/paste this link</span> <span class="token comment">// to someone else and they will see the same UI.</span> <span class="token comment">//</span> <span class="token comment">// Then click the back button and watch the last</span> <span class="token comment">// segment of the URL disappear along with the last</span> <span class="token comment">// friend list.</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">RecursiveExample</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Router<span class="token operator">></span> <span class="token operator"><</span>Switch<span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/:id"</span><span class="token operator">></span> <span class="token operator"><</span>Person <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Route<span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/"</span><span class="token operator">></span> <span class="token operator"><</span>Redirect to<span class="token operator">=</span><span class="token string">"/0"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Route<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Switch<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Router<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">Person</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">let</span> <span class="token punctuation">{ </span> url <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useRouteMatch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> <span class="token punctuation">{ </span> id <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useParams</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> person <span class="token operator">=</span> <span class="token function">find</span><span class="token punctuation">(</span><span class="token function">parseInt</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>h3<span class="token operator">></span><span class="token punctuation">{ </span>person<span class="token punctuation">.</span>name<span class="token punctuation">}</span>’s Friends<span class="token operator"><</span><span class="token operator">/</span>h3<span class="token operator">></span> <span class="token operator"><</span>ul<span class="token operator">></span> <span class="token punctuation">{ </span>person<span class="token punctuation">.</span>friends<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>id <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span>li key<span class="token operator">=</span><span class="token punctuation">{ </span>id<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Link to<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token template-string"><span class="token string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${ </span>url<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${ </span>id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">}</span><span class="token operator">></span><span class="token punctuation">{ </span><span class="token function">find</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>Link<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>li<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>ul<span class="token operator">></span> <span class="token operator"><</span>Switch<span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token template-string"><span class="token string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${ </span>url<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/:id`</span></span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Person <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Route<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Switch<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> <span class="token constant">PEEPS</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">{ </span> id<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"Michelle"</span><span class="token punctuation">,</span> friends<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{ </span> id<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"Sean"</span><span class="token punctuation">,</span> friends<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{ </span> id<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"Kim"</span><span class="token punctuation">,</span> friends<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{ </span> id<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"David"</span><span class="token punctuation">,</span> friends<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">find</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token constant">PEEPS</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span>p <span class="token operator">=></span> p<span class="token punctuation">.</span>id <span class="token operator">===</span> id<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <h3>code spliting</h3> <h3>HashRouter和BrowserRouter的区别,前端路由和后端路由的区别。</h3> <h3>NavLink的使用</h3> <p>NavLink是一个特殊版本的Link,可以使用activeClassName来设置Link被选中时被附加的class,使用activeStyle来配置被选中时应用的样式。此外,还有一个exact属性,此属性要求location完全匹配才会附加class和style。这里说的匹配是指地址栏中的URl和这个Link的to指定的location相匹配。</p> <pre><code class="prism language-js"><span class="token comment">// 选中后被添加class selected</span> <span class="token operator"><</span>NavLink to<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token string">'/'</span><span class="token punctuation">}</span> exact activeClassName<span class="token operator">=</span><span class="token string">'selected'</span><span class="token operator">></span>Home<span class="token operator"><</span><span class="token operator">/</span>NavLink<span class="token operator">></span> <span class="token comment">// 选中后被附加样式 color:red</span> <span class="token operator"><</span>NavLink to<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token string">'/gallery'</span><span class="token punctuation">}</span> activeStyle<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">{ </span>color<span class="token punctuation">:</span>red<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span>Gallery<span class="token operator"><</span><span class="token operator">/</span>NavLink<span class="token operator">></span> </code></pre> <blockquote> <pre><code>activeClassName`默认值为 `active </code></pre> </blockquote> <p>属性</p> <ul> <li>to 可以是字符串或者对象,同Link组件</li> <li>exact 布尔类型,完全匹配时才会被附件class和style</li> <li>activeStyle Object类型</li> <li>activeClassName 字符串类型</li> <li>strict: bool类型,当值为 <code>true</code> 时,在确定位置是否与当前 URL 匹配时,将考虑位置 <code>pathname</code> 后的斜线。</li> </ul> <h3>几个hook的钩子介绍</h3> <h4>useParams</h4> <p>这个函数什么用呢?首先我们看一个不适用<code>hooks</code>读取路由<code>params</code>的方法:</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> ReactDOM <span class="token keyword">from</span> <span class="token string">"react-dom"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{ </span> BrowserRouter <span class="token keyword">as</span> Router<span class="token punctuation">,</span> Route<span class="token punctuation">,</span> Switch <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-router-dom"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">BlogPost</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> match <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">let</span> <span class="token punctuation">{ </span> slug <span class="token punctuation">}</span> <span class="token operator">=</span> match<span class="token punctuation">.</span>params<span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token operator"><</span>div<span class="token operator">></span><span class="token punctuation">{ </span>slug<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span> <span class="token operator"><</span>Router<span class="token operator">></span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>Switch<span class="token operator">></span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/blog/:slug"</span> component<span class="token operator">=</span><span class="token punctuation">{ </span>BlogPost<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Switch<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Router<span class="token operator">></span><span class="token punctuation">,</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"root"</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <p>可以看到,我们必须使用<code>match</code>来获取路由中的<code>params</code>。</p> <p>那么如果使用<code>useParams</code>怎么做呢?</p> <pre><code class="prism language-jsx">import React from "react"; import ReactDOM from "react-dom"; import { BrowserRouter as Router, Route, Switch, useParams } from "react-router-dom"; function BlogPost() { let { slug } = useParams(); return <div>{slug}</div>; } ReactDOM.render( <Router> <div> <Switch> <Route path="/blog/:slug"> <BlogPost /> </Route> </Switch> </div> </Router>, document.getElementById("root") ); </code></pre> <p>在<code>Route</code>中我们可以不用写烦人的<code>component</code>了,只要记得用把页面包裹起来就行了,同时<code>useParams</code>的组件中也不用再写<code>{match}</code>了。</p> <p>同时嵌套路由也变得更加简单了,我们如果需要两个<code>params</code>参数的话,只要在<code>useParams</code>中传递结构得到两个参数即可。</p> <h4>useLocation</h4> <p>这个钩子函数顾名思义,可以查看当前路由:</p> <p>(也可以用这种方法在route或redirect的to里加参数,然后用location获取)</p> <pre><code class="prism language-js"><span class="token keyword">function</span> <span class="token function">BlogPost</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> <span class="token punctuation">{ </span> slug <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useParams</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> location <span class="token operator">=</span> <span class="token function">useLocation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>location<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token operator"><</span>div<span class="token operator">></span><span class="token punctuation">{ </span>slug<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>控制台会输出:</p> <pre><code class="prism language-js">Object <span class="token punctuation">{ </span>pathname<span class="token punctuation">:</span> <span class="token string">"/blog/4"</span><span class="token punctuation">,</span> search<span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">,</span> hash<span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">,</span> state<span class="token punctuation">:</span> undefined<span class="token punctuation">}</span> pathname<span class="token punctuation">:</span> <span class="token string">"/blog/4"</span> search<span class="token punctuation">:</span> <span class="token string">""</span> hash<span class="token punctuation">:</span> <span class="token string">""</span> state<span class="token punctuation">:</span> undefined </code></pre> <p><strong>一般和useEffect一起用,大家自己思考业务场景吧。</strong></p> <h4>useHistory</h4> <p>这个API还会大改,只是<code>useNavigate</code>的一个雏形,也是很好理解,可以返回上一个网页:</p> <pre><code class="prism language-js"><span class="token keyword">function</span> <span class="token function">BackButton</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">let</span> history <span class="token operator">=</span> <span class="token function">useHistory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token operator"><</span>button type<span class="token operator">=</span><span class="token string">"button"</span> onClick<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> history<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">"/blog/1"</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token number">123</span> <span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span>button type<span class="token operator">=</span><span class="token string">"button"</span> onClick<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> history<span class="token punctuation">.</span><span class="token function">goBack</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span> 回去 <span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <h4>useRouteMatch</h4> <p><code>useRouteMatch</code>挂钩尝试以与<code><Route></code>相同的方式匹配当前<code>URL</code>。在无需实际呈现<code><Route></code>的情况下访问匹配数据最有用。</p> <pre><code class="prism language-js"><span class="token comment">// before</span> <span class="token keyword">import</span> <span class="token punctuation">{ </span> Route <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-router-dom'</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token punctuation">{ </span><span class="token comment">/* ... */</span><span class="token punctuation">}</span> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/BLOG/:slug/"</span> strict sensitive render<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">(</span><span class="token punctuation">{ </span> match <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> match <span class="token operator">?</span> <span class="token operator"><</span>BlogPost match<span class="token operator">=</span><span class="token punctuation">{ </span>match<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">:</span> <span class="token operator"><</span>NotFound <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">// after</span> <span class="token keyword">import</span> <span class="token punctuation">{ </span> useRouteMatch <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-router-dom'</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">let</span> match <span class="token operator">=</span> <span class="token function">useRouteMatch</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> path<span class="token punctuation">:</span> <span class="token string">'/BLOG/:slug/'</span><span class="token punctuation">,</span> strict<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> sensitive<span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token punctuation">{ </span><span class="token comment">/* ... */</span><span class="token punctuation">}</span> <span class="token punctuation">{ </span>match <span class="token operator">?</span> <span class="token operator"><</span>BlogPost match<span class="token operator">=</span><span class="token punctuation">{ </span>match<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">:</span> <span class="token operator"><</span>NotFound <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre> <h2>2、React Router基本原理</h2> <p>React Router甚至大部分的前端路由都是依赖于<code>history.js</code>的,它是一个独立的第三方js库。可以用来兼容在不同浏览器、不同环境下对历史记录的管理,拥有统一的API。</p> <ul> <li>老浏览器的history: 通过<code>hash</code>来存储在不同状态下的<code>history</code>信息,对应<code>createHashHistory</code>,通过检测<code>location.hash</code>的值的变化,使用<code>location.replace</code>方法来实现url跳转。通过注册监听<code>window</code>对象上的<code>hashChange</code>事件来监听路由的变化,实现历史记录的回退。</li> <li>高版本浏览器: 利用HTML5里面的history,对应<code>createBrowserHistory</code>, 使用包括<code>pushState</code>, <code>replaceState</code>方法来进行跳转。通过注册监听<code>window</code>对象上的<code>popstate</code>事件来监听路由的变化,实现历史记录的回退。</li> <li>node环境下: 在内存中进行历史记录的存储,对应<code>createMemoryHistory</code>。直接在内存里<code>push</code>和<code>pop</code>状态。</li> </ul> <h1>十七、Immutable.js</h1> <h2>1、JavaScript数据修改的问题</h2> <p>看一段大家熟悉的代码</p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> state <span class="token operator">=</span> <span class="token punctuation">{ </span> str<span class="token punctuation">:</span> <span class="token string">'千锋教育'</span><span class="token punctuation">,</span> obj<span class="token punctuation">:</span> <span class="token punctuation">{ </span> y<span class="token punctuation">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> arr<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> newState <span class="token operator">=</span> state console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>newState <span class="token operator">===</span> state<span class="token punctuation">)</span> <span class="token comment">// true</span> </code></pre> <p>由于js的对象和数组都是引用类型。所以newState的state实际上是指向于同一块内存地址的, 所以结果是newState和state是相等的。</p> <p>尝试修改一下数据</p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> state <span class="token operator">=</span> <span class="token punctuation">{ </span> str<span class="token punctuation">:</span> <span class="token string">'千锋教育'</span><span class="token punctuation">,</span> obj<span class="token punctuation">:</span> <span class="token punctuation">{ </span> y<span class="token punctuation">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> arr<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> newState <span class="token operator">=</span> state newState<span class="token punctuation">.</span>str <span class="token operator">=</span> <span class="token string">'千锋教育H5学院'</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>state<span class="token punctuation">.</span>str<span class="token punctuation">,</span> newState<span class="token punctuation">.</span>str<span class="token punctuation">)</span> </code></pre> <p>可以看到,newState的修改也会引起state的修改。要解决这个问题,js中提供了另一种修改数据的方式,要修改一个数据之前先制作一份数据的拷贝,像这样</p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> state <span class="token operator">=</span> <span class="token punctuation">{ </span> str<span class="token punctuation">:</span> <span class="token string">'千锋教育'</span><span class="token punctuation">,</span> obj<span class="token punctuation">:</span> <span class="token punctuation">{ </span> y<span class="token punctuation">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> arr<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> newState <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">assign</span><span class="token punctuation">(</span><span class="token punctuation">{ </span><span class="token punctuation">}</span><span class="token punctuation">,</span> state<span class="token punctuation">)</span> newState<span class="token punctuation">.</span>str <span class="token operator">=</span> <span class="token string">'千锋教育H5学院'</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>state<span class="token punctuation">.</span>str<span class="token punctuation">,</span> newState<span class="token punctuation">.</span>str<span class="token punctuation">)</span> </code></pre> <p>我们可以使用很多方式在js中复制数据,比如<code>…</code>, <code>Object.assign</code>, <code>Object.freeze</code>, <code>slice</code>, <code>concat</code>, <code>map</code>, <code>filter</code>, <code>reduce</code>等方式进行复制,但这些都是浅拷贝,就是只拷贝第一层数据,更深层的数据还是同一个引用,比如:</p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> state <span class="token operator">=</span> <span class="token punctuation">{ </span> str<span class="token punctuation">:</span> <span class="token string">'千锋教育'</span><span class="token punctuation">,</span> obj<span class="token punctuation">:</span> <span class="token punctuation">{ </span> y<span class="token punctuation">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> arr<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> newState <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">assign</span><span class="token punctuation">(</span><span class="token punctuation">{ </span><span class="token punctuation">}</span><span class="token punctuation">,</span> state<span class="token punctuation">)</span> newState<span class="token punctuation">.</span>obj<span class="token punctuation">.</span>y <span class="token operator">=</span> <span class="token number">2</span> newState<span class="token punctuation">.</span>arr<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>state<span class="token punctuation">,</span> newState<span class="token punctuation">)</span> </code></pre> <p>可以看到,当在更改newState更深层次的数据的时候,还是会影响到state的值。如果要深层复制,就得一层一层的做递归拷贝,这是一个复杂的问题。虽然有些第三方的库已经帮我们做好了,比如<code>lodash</code>的<code>cloneDeep</code>方法。深拷贝是非常消耗性能的。</p> <pre><code class="prism language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{ </span> cloneDeep <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'lodash'</span> <span class="token keyword">const</span> state <span class="token operator">=</span> <span class="token punctuation">{ </span> str<span class="token punctuation">:</span> <span class="token string">'千锋教育'</span><span class="token punctuation">,</span> obj<span class="token punctuation">:</span> <span class="token punctuation">{ </span> y<span class="token punctuation">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> arr<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> newState <span class="token operator">=</span> <span class="token function">cloneDeep</span><span class="token punctuation">(</span>state<span class="token punctuation">)</span> newState<span class="token punctuation">.</span>obj<span class="token punctuation">.</span>y <span class="token operator">=</span> <span class="token number">2</span> newState<span class="token punctuation">.</span>arr<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>state<span class="token punctuation">,</span> newState<span class="token punctuation">)</span> </code></pre> <h2>2、什么是不可变数据</h2> <p>不可变数据 (Immutable Data )就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。Immutable 实现的原理是持久化数据结构( Persistent Data Structure),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用了 结构共享(Structural Sharing),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。</p> <p><a href="http://img.e-com-net.com/image/info8/d1b8fe1c1a784d609fe255d06f23a188.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/d1b8fe1c1a784d609fe255d06f23a188.jpg" alt="2021react复习_第5张图片" width="650" height="295" style="border:1px solid black;"></a></p> <h2>3、immutable.js的优缺点</h2> <p><strong>优点:</strong></p> <ul> <li>降低mutable带来的复杂度(可以减少state更新导致的渲染变多)</li> <li>节省内存</li> <li>历史追溯性(时间旅行):时间旅行指的是,每时每刻的值都被保留了,想回退到哪一步只要简单的将数据取出就行,想一下如果现在页面有个撤销的操作,撤销前的数据被保留了,只需要取出就行,这个特性在redux或者flux中特别有用</li> <li>拥抱函数式编程:immutable本来就是函数式编程的概念,纯函数式编程的特点就是,只要输入一致,输出必然一致,相比于面向对象,这样开发组件和调试更方便。推荐一本函数式编程的在线免费书《JS 函数式编程指南》。</li> </ul> <p><strong>缺点:</strong></p> <ul> <li>需要重新学习api</li> <li>资源包大小增加(源码5000行左右)</li> <li>容易与原生对象混淆:由于api与原生不同,混用的话容易出错。</li> </ul> <h2>4、使用Immutable.js</h2> <p>immutable在进行操作的时候原对象是不会发生改变的,但会返回一个改变后的对象出来(自己理解)</p> <p>也因为这个原因,之前对象的数据都保存着,和git很像,所以能做时间旅行,返回到之前的状态</p> <p><strong>01-get-started</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> Map <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> map1 <span class="token operator">=</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> c<span class="token punctuation">:</span> <span class="token number">3</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">const</span> map2 <span class="token operator">=</span> map1<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token string">'b'</span><span class="token punctuation">,</span> <span class="token number">50</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>map1<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">'b'</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">' vs. '</span> <span class="token operator">+</span> map2<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">'b'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">*</span><span class="token comment">// 2 vs. 50*</span> </code></pre> <p><strong>02-case-for-immutability-1.js</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> Map <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> map1 <span class="token operator">=</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> c<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">const</span> map2 <span class="token operator">=</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> c<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">}</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>map1<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>map2<span class="token punctuation">)</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>map1 <span class="token operator">==</span> map2<span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>map1 <span class="token operator">===</span> map2<span class="token punctuation">)</span> <span class="token comment">// true</span> <span class="token comment">// false</span> <span class="token comment">// false</span> </code></pre> <p><strong>02-case-for-immutability-2.js</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> Map <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> map1 <span class="token operator">=</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> c<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">const</span> map2 <span class="token operator">=</span> map1<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token string">'b'</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>map1<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>map2<span class="token punctuation">)</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>map1 <span class="token operator">==</span> map2<span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>map1 <span class="token operator">===</span> map2<span class="token punctuation">)</span> <span class="token comment">// true</span> <span class="token comment">// true</span> <span class="token comment">// true</span> </code></pre> <p><strong>02-case-for-immutability-3.js</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> Map <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> map <span class="token operator">=</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> c<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">const</span> mapCopy <span class="token operator">=</span> map console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>mapCopy<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>map<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// true</span> </code></pre> <p><strong>03-JavaScript-first-API-0.js</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> List <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> list1 <span class="token operator">=</span> <span class="token function">List</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token keyword">const</span> list2 <span class="token operator">=</span> list1<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span> <span class="token keyword">const</span> list3 <span class="token operator">=</span> list2<span class="token punctuation">.</span><span class="token function">unshift</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword">const</span> list4 <span class="token operator">=</span> list1<span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>list2<span class="token punctuation">,</span> list3<span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>list1<span class="token punctuation">.</span>size <span class="token operator">===</span> <span class="token number">2</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>list2<span class="token punctuation">.</span>size <span class="token operator">===</span> <span class="token number">5</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>list3<span class="token punctuation">.</span>size <span class="token operator">===</span> <span class="token number">6</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>list4<span class="token punctuation">.</span>size <span class="token operator">===</span> <span class="token number">13</span><span class="token punctuation">)</span> <span class="token comment">// true</span> <span class="token comment">// true</span> <span class="token comment">// true</span> <span class="token comment">// true</span> </code></pre> <p><strong>03-JavaScript-first-API-1.js</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> Map <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> alpha <span class="token operator">=</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> c<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">,</span> d<span class="token punctuation">:</span> <span class="token number">4</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">const</span> upperCase <span class="token operator">=</span> alpha<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>v<span class="token punctuation">,</span> k<span class="token punctuation">)</span> <span class="token operator">=></span> k<span class="token punctuation">.</span><span class="token function">toUpperCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>upperCase<span class="token punctuation">)</span> <span class="token comment">// A,B,C,D</span> </code></pre> <p><strong>03-JavaScript-first-API-2.js</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> Map<span class="token punctuation">,</span> List <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> map1 <span class="token operator">=</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> c<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">,</span> d<span class="token punctuation">:</span> <span class="token number">4</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> map2 <span class="token operator">=</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> c<span class="token punctuation">:</span> <span class="token number">10</span><span class="token punctuation">,</span> a<span class="token punctuation">:</span> <span class="token number">20</span><span class="token punctuation">,</span> t<span class="token punctuation">:</span> <span class="token number">30</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{ </span> d<span class="token punctuation">:</span> <span class="token number">100</span><span class="token punctuation">,</span> o<span class="token punctuation">:</span> <span class="token number">200</span><span class="token punctuation">,</span> g<span class="token punctuation">:</span> <span class="token number">300</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">const</span> map3 <span class="token operator">=</span> map1<span class="token punctuation">.</span><span class="token function">merge</span><span class="token punctuation">(</span>map2<span class="token punctuation">,</span> obj<span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>map3<span class="token punctuation">)</span> <span class="token comment">// Map { "a": 20, "b": 2, "c": 10, "d": 100, "t": 30, "o": 200, "g": 300 }</span> <span class="token keyword">const</span> list1 <span class="token operator">=</span> <span class="token function">List</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> list2 <span class="token operator">=</span> <span class="token function">List</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">6</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> array <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">9</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">const</span> list3 <span class="token operator">=</span> list1<span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>list2<span class="token punctuation">,</span> array<span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>list3<span class="token punctuation">)</span> <span class="token comment">// List [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]</span> </code></pre> <p><strong>03-JavaScript-first-API-3.js</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> Seq <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> myObject <span class="token operator">=</span> <span class="token punctuation">{ </span>a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> c<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">}</span> <span class="token keyword">const</span> seq <span class="token operator">=</span> <span class="token function">Seq</span><span class="token punctuation">(</span>myObject<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>v <span class="token operator">=></span> v <span class="token operator">*</span> v<span class="token punctuation">)</span> <span class="token keyword">const</span> seqToObject <span class="token operator">=</span> seq<span class="token punctuation">.</span><span class="token function">toObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>seq<span class="token punctuation">,</span> seqToObject<span class="token punctuation">)</span> <span class="token comment">// Seq { "a": 1, "b": 4, "c": 9 } { a: 1, b: 4, c: 9 }</span> </code></pre> <p><strong>03-JavaScript-first-API-4.js</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> fromJS <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{ </span> <span class="token number">1</span><span class="token punctuation">:</span> <span class="token string">'one'</span> <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">*</span><span class="token comment">// [ '1' ]*</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj<span class="token punctuation">[</span><span class="token string">'1'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> obj<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">*</span><span class="token comment">// one one*</span> <span class="token keyword">const</span> map <span class="token operator">=</span> <span class="token function">fromJS</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>map<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">'1'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> map<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">*</span><span class="token comment">// one undefined*</span> </code></pre> <p><strong>03-JavaScript-first-API-5.js</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> Map<span class="token punctuation">,</span> List <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> deep <span class="token operator">=</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> c<span class="token punctuation">:</span> <span class="token function">List</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span> <span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>deep<span class="token punctuation">.</span><span class="token function">toObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>deep<span class="token punctuation">.</span><span class="token function">toArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>deep<span class="token punctuation">.</span><span class="token function">toJS</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>deep<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// { a: 1, b: 2, c: List [ 3, 4, 5 ] }</span> <span class="token comment">// [ 1, 2, List [ 3, 4, 5 ] ]</span> <span class="token comment">// { a: 1, b: 2, c: [ 3, 4, 5 ] }</span> <span class="token comment">// {"a":1,"b":2,"c":[3,4,5]}</span> </code></pre> <p><strong>03-JavaScript-first-API-6.js</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> Map<span class="token punctuation">,</span> List <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> mapped <span class="token operator">=</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> c<span class="token punctuation">:</span> <span class="token number">3</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>mapped<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>x <span class="token operator">=></span> x <span class="token operator">*</span> x<span class="token punctuation">)</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>mapped<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span>x<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> x <span class="token operator">*</span> x <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// Map { "a": 1, "b": 4, "c": 9 }</span> <span class="token comment">// Map { "a": 1, "b": 4, "c": 9 }</span> <span class="token keyword">const</span> aList <span class="token operator">=</span> <span class="token function">List</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span> <span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token keyword">const</span> anArray <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token operator">...</span>aList<span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span> <span class="token punctuation">]</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>anArray<span class="token punctuation">)</span> <span class="token comment">// [ 0, 1, 2, 3, 4, 5 ]</span> </code></pre> <p><strong>04-nested-structures.js</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> fromJS <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> nested <span class="token operator">=</span> <span class="token function">fromJS</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token punctuation">{ </span> b<span class="token punctuation">:</span> <span class="token punctuation">{ </span> c<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>nested<span class="token punctuation">)</span> <span class="token comment">// Map { "a": Map { "b": Map { "c": List [ 3, 4, 5 ] } } }</span> <span class="token keyword">const</span> nested2 <span class="token operator">=</span> nested<span class="token punctuation">.</span><span class="token function">mergeDeep</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token punctuation">{ </span> b<span class="token punctuation">:</span> <span class="token punctuation">{ </span> d<span class="token punctuation">:</span> <span class="token number">6</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>nested2<span class="token punctuation">)</span> <span class="token comment">// Map { "a": Map { "b": Map { "c": List [ 3, 4, 5 ], "d": 6 } } }*</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>nested2<span class="token punctuation">.</span><span class="token function">getIn</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token string">'a'</span><span class="token punctuation">,</span> <span class="token string">'b'</span><span class="token punctuation">,</span> <span class="token string">'d'</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// 6</span> <span class="token keyword">const</span> nested3 <span class="token operator">=</span> nested2<span class="token punctuation">.</span><span class="token function">updateIn</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token string">'a'</span><span class="token punctuation">,</span> <span class="token string">'b'</span><span class="token punctuation">,</span> <span class="token string">'d'</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> value <span class="token operator">=></span> value <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>nested3<span class="token punctuation">)</span> <span class="token comment">// Map { "a": Map { "b": Map { "c": "List [ 3, 4, 5 ]1", "d": 7 } } }</span> <span class="token comment">// setIn 和 updateIn 都可以修改深层次的Immutable对象,setIn 直接传值,updateIn 传入回调函数</span> <span class="token keyword">const</span> nested4 <span class="token operator">=</span> nested3<span class="token punctuation">.</span><span class="token function">updateIn</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token string">'a'</span><span class="token punctuation">,</span> <span class="token string">'b'</span><span class="token punctuation">,</span> <span class="token string">'c'</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> list <span class="token operator">=></span> list<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>nested4<span class="token punctuation">)</span> <span class="token comment">// Map { "a": Map { "b": Map { "c": List [ 3, 4, 5, 6 ], "d": 7 } } }</span> <span class="token keyword">const</span> nested5 <span class="token operator">=</span> nested4<span class="token punctuation">.</span><span class="token function">setIn</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'a'</span><span class="token punctuation">,</span> <span class="token string">'b'</span><span class="token punctuation">,</span> <span class="token string">'d'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">90</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>nested5<span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>nested<span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>nested2<span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>nested3<span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>nested4<span class="token punctuation">)</span> <span class="token comment">// Map { "a": Map { "b": Map { "c": List [ 3, 4, 5 ] } } }</span> <span class="token comment">// Map { "a": Map { "b": Map { "c": List [ 3, 4, 5 ], "d": 6 } } }</span> <span class="token comment">// Map { "a": Map { "b": Map { "c": List [ 3, 4, 5 ], "d": 7 } } }</span> <span class="token comment">// Map { "a": Map { "b": Map { "c": List [ 3, 4, 5, 6 ], "d": 7 } } }</span> </code></pre> <p><strong>05-Equality-treats-Collections-as-Values-0.js</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> Map<span class="token punctuation">,</span> is <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> obj1 <span class="token operator">=</span> <span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> c<span class="token punctuation">:</span> <span class="token number">3</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">const</span> obj2 <span class="token operator">=</span> <span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> c<span class="token punctuation">:</span> <span class="token number">3</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj1 <span class="token operator">!==</span> obj2<span class="token punctuation">)</span> <span class="token comment">// true</span> <span class="token keyword">const</span> map1 <span class="token operator">=</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> c<span class="token punctuation">:</span> <span class="token number">3</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> map2 <span class="token operator">=</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> c<span class="token punctuation">:</span> <span class="token number">3</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>map1 <span class="token operator">!==</span> map2<span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>map1<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>map2<span class="token punctuation">)</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">is</span><span class="token punctuation">(</span>map1<span class="token punctuation">,</span> map2<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// true</span> <span class="token comment">// true</span> <span class="token comment">// true</span> </code></pre> <p><strong>05-Equality-treats-Collections-as-Values-1.js</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> Map<span class="token punctuation">,</span> Set <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> map1 <span class="token operator">=</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> c<span class="token punctuation">:</span> <span class="token number">3</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> map2 <span class="token operator">=</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> c<span class="token punctuation">:</span> <span class="token number">3</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token keyword">set</span> <span class="token operator">=</span> <span class="token function">Set</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>map1<span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">set</span><span class="token punctuation">.</span><span class="token function">has</span><span class="token punctuation">(</span>map2<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// true</span> </code></pre> <p><strong>05-Equality-treats-Collections-as-Values-2.js</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> Map <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> originalMap <span class="token operator">=</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> c<span class="token punctuation">:</span> <span class="token number">3</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> updatedMap <span class="token operator">=</span> originalMap<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token string">'b'</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>updatedMap <span class="token operator">===</span> originalMap<span class="token punctuation">)</span> <span class="token comment">// true</span> </code></pre> <p><strong>05-Equality-treats-Collections-as-Values-3.js</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> Map<span class="token punctuation">,</span> is <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> originalMap <span class="token operator">=</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> c<span class="token punctuation">:</span> <span class="token number">3</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> updatedMap <span class="token operator">=</span> originalMap<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token string">'b'</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>updatedMap <span class="token operator">!==</span> originalMap<span class="token punctuation">)</span> <span class="token comment">// true</span> <span class="token keyword">const</span> anotherUpdatedMap <span class="token operator">=</span> originalMap<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token string">'b'</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>anotherUpdatedMap <span class="token operator">!==</span> updatedMap<span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>anotherUpdatedMap<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>updatedMap<span class="token punctuation">)</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">is</span><span class="token punctuation">(</span>anotherUpdatedMap<span class="token punctuation">,</span> updatedMap<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// true</span> <span class="token comment">// true</span> <span class="token comment">// true</span> </code></pre> <p><strong>06-Batching-Mutations.js</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> List <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> list1 <span class="token operator">=</span> <span class="token function">List</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> list2 <span class="token operator">=</span> list1<span class="token punctuation">.</span><span class="token function">withMutations</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span>list<span class="token punctuation">)</span> <span class="token punctuation">{ </span> list<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>list1<span class="token punctuation">.</span>size <span class="token operator">===</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>list2<span class="token punctuation">.</span>size <span class="token operator">===</span> <span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span> <span class="token comment">// true</span> <span class="token keyword">let</span> map2 <span class="token operator">=</span> map1<span class="token punctuation">.</span><span class="token function">withMutations</span><span class="token punctuation">(</span><span class="token punctuation">(</span>map<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token comment">// 逻辑</span> map<span class="token punctuation">.</span><span class="token function">setIn</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'c'</span><span class="token punctuation">,</span> <span class="token string">'d'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">)</span> map<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token string">'a'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">let</span> map3 <span class="token operator">=</span> map1<span class="token punctuation">.</span><span class="token function">updateIn</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'c'</span><span class="token punctuation">,</span> <span class="token string">'d'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>v<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token number">9</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>map1 <span class="token operator">===</span> map3<span class="token punctuation">)</span> </code></pre> <p><strong>07-Lazy-Seq-0.js</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> Seq <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> oddSquares <span class="token operator">=</span> <span class="token function">Seq</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">8</span> <span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>x <span class="token operator">=></span> <span class="token punctuation">{ </span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'filter x:'</span> <span class="token operator">+</span> x<span class="token punctuation">)</span> <span class="token keyword">return</span> x <span class="token operator">%</span> <span class="token number">2</span> <span class="token operator">!==</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>x <span class="token operator">=></span> <span class="token punctuation">{ </span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'map x:'</span> <span class="token operator">+</span> x<span class="token punctuation">)</span> <span class="token keyword">return</span> x <span class="token operator">*</span> x <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>oddSquares<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// filter x:1</span> <span class="token comment">// filter x:2</span> <span class="token comment">// filter x:3</span> <span class="token comment">// map x:3</span> <span class="token comment">// 9</span> </code></pre> <p><strong>07-Lazy-Seq-1.js</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> Seq<span class="token punctuation">,</span> Map <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> map <span class="token operator">=</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> c<span class="token punctuation">:</span> <span class="token number">3</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> lazySeq <span class="token operator">=</span> <span class="token function">Seq</span><span class="token punctuation">(</span>map<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> newMap <span class="token operator">=</span> lazySeq <span class="token punctuation">.</span><span class="token function">flip</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>key <span class="token operator">=></span> key<span class="token punctuation">.</span><span class="token function">toUpperCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">flip</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>newMap<span class="token punctuation">)</span> <span class="token comment">// Seq { A: 1, B: 1, C: 1 }</span> </code></pre> <p><strong>07-Lazy-Seq-2.js</strong></p> <pre><code class="prism language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{ </span> Range <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'immutable'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> aRange <span class="token operator">=</span> <span class="token function">Range</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">Infinity</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">skip</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>n <span class="token operator">=></span> <span class="token operator">-</span>n<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>n <span class="token operator">=></span> n <span class="token operator">%</span> <span class="token number">2</span> <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">take</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span>r<span class="token punctuation">,</span> n<span class="token punctuation">)</span> <span class="token operator">=></span> r <span class="token operator">*</span> n<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>aRange<span class="token punctuation">)</span> <span class="token comment">// 1006008</span> </code></pre> <h2>5、在redux中使用immutable.js</h2> <p>redux官网推荐使用redux-immutable进行redux和immutable的集成。几个注意点:</p> <p><code>redux</code>中,利用<code>combineReducers</code>来合并多个<code>reduce</code>, <code>redux</code>自带的<code>combineReducers</code>只支持原生js形式的,所以需要使用<code>redux-immutable</code>提供的<code>combineReducers</code>来代替</p> <pre><code class="prism language-js"><span class="token comment">// 使用redux-immutable提供的combineReducers方法替换redux里的combineReducers</span> <span class="token keyword">import</span> <span class="token punctuation">{ </span>combineReducers<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'redux-immutable'</span> <span class="token keyword">import</span> reducerOne <span class="token keyword">from</span> <span class="token string">'./reducerOne'</span> <span class="token keyword">import</span> reducerTwo <span class="token keyword">from</span> <span class="token string">'./reducerTwo'</span> <span class="token keyword">const</span> rootReducer <span class="token operator">=</span> <span class="token function">combineReducers</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> reducerOne<span class="token punctuation">,</span> reducerTwo <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> rootReducer<span class="token punctuation">;</span> </code></pre> <p><code>reducer</code>中的<code>initialState</code>也需要初始化成<code>immutable</code>类型, 比如一个counter的reducer</p> <pre><code class="prism language-js"><span class="token keyword">import</span> <span class="token punctuation">{ </span> Map <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'immutable'</span> <span class="token keyword">import</span> ActionTypes <span class="token keyword">from</span> <span class="token string">'../actions'</span> <span class="token keyword">const</span> initialState <span class="token operator">=</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> count<span class="token punctuation">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">(</span>state <span class="token operator">=</span> initialState<span class="token punctuation">,</span> action<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">switch</span> <span class="token punctuation">(</span>action<span class="token punctuation">.</span>type<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">case</span> ActionTypes<span class="token punctuation">.</span><span class="token constant">INCREAMENT</span><span class="token punctuation">:</span> <span class="token keyword">return</span> state<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token string">'count'</span><span class="token punctuation">,</span> state<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">'count'</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token comment">// 使用set或setIn来更改值, get或者getIn来取值</span> <span class="token keyword">case</span> ActionTypes<span class="token punctuation">.</span><span class="token constant">DECREAMENT</span><span class="token punctuation">:</span> <span class="token keyword">return</span> state<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token string">'count'</span><span class="token punctuation">,</span> state<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">'count'</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token keyword">default</span><span class="token punctuation">:</span> <span class="token keyword">return</span> state <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <p><code>state</code>成为了<code>immutable</code>类型,<code>connect</code>的<code>mapStateToProp</code>也需要相应的改变</p> <pre><code class="prism language-js"><span class="token keyword">const</span> <span class="token function-variable function">mapStateToProps</span> <span class="token operator">=</span> state <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">{ </span> count<span class="token punctuation">:</span> state<span class="token punctuation">.</span><span class="token function">getIn</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'counter'</span><span class="token punctuation">,</span> <span class="token string">'count'</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">// 永远不要在mapStateToProps里使用`toJS`方法,因为它永远返回一个新的对象</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> </code></pre> <p>在<code>shouldComponentUpdate</code>里就可以使用<code>immutable.is</code>或者<code>instance.equals</code>来进行数据的对比了。</p> <h1>十八、Lazy 和 Suspense</h1> <h2>1、React.lazy 定义</h2> <p><code>React.lazy</code> 函数能让你像渲染常规组件一样处理动态引入(的组件)。</p> <p>什么意思呢?其实就是懒加载。其原理就是利用<code>es6 import()</code>函数。这个<code>import</code>不是<code>import命令</code>。同样是引入模块,<code>import命令</code>是同步引入模块,而<code>import()</code>函数动态引入。</p> <p>当 Webpack 解析到该语法时,它会自动地开始进行代码分割(Code Splitting),分割成一个文件,当使用到这个文件的时候会这段代码才会被异步加载。</p> <h3>(1) 为什么代码要分割</h3> <p>当你的程序越来越大,代码量越来越多。一个页面上堆积了很多功能,也许有些功能很可能都用不到,但是一样下载加载到页面上,所以这里面肯定有优化空间。就如图片懒加载的理论。</p> <h3>(2) import函数</h3> <p>javascript</p> <pre><code class="prism language-javascript"><span class="token comment">//import 命令</span> <span class="token keyword">import</span> <span class="token punctuation">{ </span> add <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./math'</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">,</span> <span class="token number">26</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//import函数</span> <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token string">"./math"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>math <span class="token operator">=></span> <span class="token punctuation">{ </span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>math<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">,</span> <span class="token number">26</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <blockquote> <p>动态 <code>import()</code> 语法目前只是一个 ECMAScript (JavaScript) 提案, 而不是正式的语法标准。预计在不远的将来就会被正式接受。http://es6.ruanyifeng.com/#docs/module#import</p> </blockquote> <h3>(3) import函数示例</h3> <p>下面是import一个示例:</p> <p>在test文件夹下新建两个文件</p> <p><a href="http://img.e-com-net.com/image/info8/c9a35ab87fb846cab306987ba02299cd.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/c9a35ab87fb846cab306987ba02299cd.jpg" alt="图片1" width="390" height="67"></a></p> <p><strong>图片1:</strong></p> <p>test.html代码如下:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>root<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> 页面无内容 <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>btn<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>加载js<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script language-javascript"> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'btn'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function-variable function">onclick</span><span class="token operator">=</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{ </span> <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token string">'./test.js'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>d<span class="token operator">=></span><span class="token punctuation">{ </span> d<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> </code></pre> <p>test.js代码如下:</p> <pre><code class="prism language-javascript"><span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{ </span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'root'</span><span class="token punctuation">)</span> root<span class="token punctuation">.</span>innerHTML<span class="token operator">=</span><span class="token string">'页面变的有内容了'</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token punctuation">{ </span>test<span class="token punctuation">}</span> </code></pre> <p><a href="http://img.e-com-net.com/image/info8/f27792256a1b44ddb6c31678db58913e.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/f27792256a1b44ddb6c31678db58913e.jpg" alt="2021react复习_第6张图片" width="650" height="370" style="border:1px solid black;"></a></p> <p><strong>图片2</strong></p> <p>这时候打开web服务让页面以http的方式访问,http://192.168.1.2:8080/test.html</p> <p>我们在chrome的开发者工具下的Network可以看到只请求了一个页面。</p> <p><a href="http://img.e-com-net.com/image/info8/da90036489bb4cd48692faf27f6dd41f.png" target="_blank"><img src="http://img.e-com-net.com/image/info8/da90036489bb4cd48692faf27f6dd41f.png" alt="2021react复习_第7张图片" width="465" height="264" style="border:1px solid black;"></a></p> <p><strong>图片3</strong></p> <p>但是当我们点击加载js,你会发现test.js会以动态的方式加入到代码中,同时执行了test函数,使页面的内容发生了变化。</p> <p><a href="http://img.e-com-net.com/image/info8/9946f8836918433e8c343ac6bda998e2.png" target="_blank"><img src="http://img.e-com-net.com/image/info8/9946f8836918433e8c343ac6bda998e2.png" alt="2021react复习_第8张图片" width="533" height="267" style="border:1px solid black;"></a></p> <p><strong>图片4</strong></p> <p>在<code>React.lazy</code>和常用的三方包<code>react-loadable</code>,都是使用了这个原理,然后配合webpack进行代码打包拆分达到异步加载,这样首屏渲染的速度将大大的提高。</p> <p>由于<code>React.lazy</code>不支持服务端渲染,所以这时候<code>react-loadable</code>就是不错的选择。</p> <h2>2、如何使用React.lazy</h2> <p>下面示例代码使用create-react-app脚手架搭建:</p> <pre><code class="prism language-js"><span class="token comment">//OtherComponent.js 文件内容</span> <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">const</span> <span class="token function-variable function">OtherComponent</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> 我已加载 <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> OtherComponent <span class="token comment">// App.js 文件内容</span> <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token string">'./App.css'</span><span class="token punctuation">;</span> <span class="token comment">//使用React.lazy导入OtherComponent组件</span> <span class="token keyword">const</span> OtherComponent <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">lazy</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token string">'./OtherComponent'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"App"</span><span class="token operator">></span> <span class="token operator"><</span>OtherComponent<span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span> </code></pre> <p>这是最简单的<code>React.lazy</code>,但是这样页面会报错。这个报错提示我们,在React使用了<code>lazy</code>之后,会存在一个加载中的空档期,React不知道在这个空档期中该显示什么内容,所以需要我们指定。接下来就要使用到<code>Suspense</code>。</p> <p><a href="http://img.e-com-net.com/image/info8/9142e5054e5f469683834d61af4e0d38.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/9142e5054e5f469683834d61af4e0d38.jpg" alt="2021react复习_第9张图片" width="551" height="589" style="border:1px solid black;"></a></p> <p><strong>图片5</strong></p> <h3>(1) Suspense</h3> <p>如果在 <code>App</code> 渲染完成后,包含 <code>OtherComponent</code> 的模块还没有被加载完成,我们可以使用加载指示器为此组件做优雅降级。这里我们使用 <code>Suspense</code> 组件来解决。</p> <p>这里将<code>App</code>组件改一改</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> Suspense<span class="token punctuation">,</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token string">'./App.css'</span><span class="token punctuation">;</span> <span class="token comment">//使用React.lazy导入OtherComponent组件</span> <span class="token keyword">const</span> OtherComponent <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">lazy</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token string">'./OtherComponent'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> state <span class="token operator">=</span> <span class="token punctuation">{ </span> visible<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"App"</span><span class="token operator">></span> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> visible<span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">></span> 加载OtherComponent组件 <span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span>Suspense fallback<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token operator"><</span>div<span class="token operator">></span>Loading<span class="token operator">...</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>visible <span class="token operator">?</span> <span class="token operator"><</span>OtherComponent <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">:</span> <span class="token keyword">null</span> <span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>Suspense<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <p>我们指定了空档期使用Loading展示在界面上面,等<code>OtherComponent</code>组件异步加载完毕,把<code>OtherComponent</code>组件的内容替换掉Loading上。</p> <p><a href="http://img.e-com-net.com/image/info8/125e4476bda44a7a9c098aa9a7b544c5.gif" target="_blank"><img src="http://img.e-com-net.com/image/info8/125e4476bda44a7a9c098aa9a7b544c5.gif" alt="2021react复习_第10张图片" width="936" height="437" style="border:1px solid black;"></a></p> <p><strong>图片6</strong></p> <p><a href="http://img.e-com-net.com/image/info8/c5b5c7e2012643b6ace7623fbbb699dd.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/c5b5c7e2012643b6ace7623fbbb699dd.jpg" alt="2021react复习_第11张图片" width="650" height="312" style="border:1px solid black;"></a></p> <p><strong>图片7</strong></p> <p>为了演示我把chrome网络调到<code>lower-end mobile</code>,不然看不到loading出现。</p> <p>可以从上面图片看出,当点击加载的时候,页面的head会插入``这段代码,发出一个get请求,页面开始显示loading,去请求<code>2.chunk.js</code>文件。</p> <p>请求结束返回内容就是<code>OtherComponent</code>组件的内容,只是文件名称和文件内容经过webpack处理过。</p> <blockquote> <p>注意:<code>Suspense</code>使用的时候,<code>fallback</code>一定是存在且有内容的, 否则会报错。</p> </blockquote> <h1>十九、React Hooks</h1> <p>在 React 的世界中,有容器组件和 UI 组件之分,在 React Hooks 出现之前,UI 组件我们可以使用函数,无状态组件来展示 UI,而对于容器组件,函数组件就显得无能为力,我们依赖于类组件来获取数据,处理数据,并向下传递参数给 UI 组件进行渲染。在我看来,使用 React Hooks 相比于从前的类组件有以下几点好处:</p> <ol> <li>代码可读性更强,原本同一块功能的代码逻辑被拆分在了不同的生命周期函数中,容易使开发者不利于维护和迭代,通过 React Hooks 可以将功能代码聚合,方便阅读维护</li> <li>组件树层级变浅,在原本的代码中,我们经常使用 HOC/render props 等方式来复用组件的状态,增强功能等,无疑增加了组件树层数及渲染,而在 React Hooks 中,这些功能都可以通过强大的自定义的 Hooks 来实现</li> </ol> <p>React 在 v16.8 的版本中推出了 React Hooks 新特性,虽然社区还没有最佳实践如何基于 React Hooks 来打造复杂应用(至少我还没有),凭借着阅读社区中大量的关于这方面的文章,下面我将通过十个案例来帮助你认识理解并可以熟练运用 React Hooks 大部分特性。</p> <h2>1、useState 保存组件状态</h2> <p>在类组件中,我们使用 <code>this.state</code> 来保存组件状态,并对其修改触发组件重新渲染。比如下面这个简单的计数器组件,很好诠释了类组件如何运行:</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{ </span> <span class="token function">constructor</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">super</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token punctuation">{ </span> count<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"alife"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> <span class="token punctuation">{ </span> count <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> Count<span class="token punctuation">:</span> <span class="token punctuation">{ </span>count<span class="token punctuation">}</span> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> count<span class="token punctuation">:</span> count <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span><span class="token operator">+</span><span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> count<span class="token punctuation">:</span> count <span class="token operator">-</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span><span class="token operator">-</span><span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <p>一个简单的计数器组件就完成了,而在函数组件中,由于没有 this 这个黑魔法,React 通过 useState 来帮我们保存组件的状态。</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> <span class="token punctuation">[</span>obj<span class="token punctuation">,</span> setObject<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> count<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"alife"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"App"</span><span class="token operator">></span> Count<span class="token punctuation">:</span> <span class="token punctuation">{ </span>obj<span class="token punctuation">.</span>count<span class="token punctuation">}</span> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setObject</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> <span class="token operator">...</span>obj<span class="token punctuation">,</span> count<span class="token punctuation">:</span> obj<span class="token punctuation">.</span>count <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span><span class="token operator">+</span><span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setObject</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> <span class="token operator">...</span>obj<span class="token punctuation">,</span> count<span class="token punctuation">:</span> obj<span class="token punctuation">.</span>count <span class="token operator">-</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span><span class="token operator">-</span><span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>通过传入 useState 参数后返回一个带有默认状态和改变状态函数的数组。通过传入新状态给函数来改变原本的状态值。<strong>值得注意的是 useState 不帮助你处理状态,相较于 setState 非覆盖式更新状态,useState 覆盖式更新状态,需要开发者自己处理逻辑。(代码如上)</strong></p> <p>似乎有个 useState 后,函数组件也可以拥有自己的状态了,但仅仅是这样完全不够。</p> <h2>2、useEffect 处理副作用</h2> <p>函数组件能保存状态,但是对于异步请求,副作用的操作还是无能为力,所以 React 提供了 useEffect 来帮助开发者处理函数组件的副作用,在介绍新 API 之前,我们先来看看类组件是怎么做的:</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{ </span> state <span class="token operator">=</span> <span class="token punctuation">{ </span> count<span class="token punctuation">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token function">componentDidMount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> <span class="token punctuation">{ </span> count <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">;</span> document<span class="token punctuation">.</span>title <span class="token operator">=</span> <span class="token string">"componentDidMount"</span> <span class="token operator">+</span> count<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>timer <span class="token operator">=</span> <span class="token function">setInterval</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> count <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">{ </span> count<span class="token punctuation">:</span> count <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">componentDidUpdate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> <span class="token punctuation">{ </span> count <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">;</span> document<span class="token punctuation">.</span>title <span class="token operator">=</span> <span class="token string">"componentDidMount"</span> <span class="token operator">+</span> count<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">componentWillUnmount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> document<span class="token punctuation">.</span>title <span class="token operator">=</span> <span class="token string">"componentWillUnmount"</span><span class="token punctuation">;</span> <span class="token function">clearInterval</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>timer<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> <span class="token punctuation">{ </span> count <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> Count<span class="token punctuation">:</span><span class="token punctuation">{ </span>count<span class="token punctuation">}</span> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">clearInterval</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>timer<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span>clear<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <p>在例子中,组件每隔一秒更新组件状态,并且每次触发更新都会触发 document.title 的更新(副作用),而在组件卸载时修改 document.title(类似于清除)</p> <p>从例子中可以看到,一些重复的功能开发者需要在 componentDidMount 和 componentDidUpdate 重复编写,而如果使用 useEffect 则完全不一样。</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> useState<span class="token punctuation">,</span> useEffect <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">let</span> timer <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> <span class="token punctuation">[</span>count<span class="token punctuation">,</span> setCount<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> document<span class="token punctuation">.</span>title <span class="token operator">=</span> <span class="token string">"componentDidMount"</span> <span class="token operator">+</span> count<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">[</span>count<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> timer <span class="token operator">=</span> <span class="token function">setInterval</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token function">setCount</span><span class="token punctuation">(</span>prevCount <span class="token operator">=></span> prevCount <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 一定注意下这个顺序:</span> <span class="token comment">// 告诉react在下次重新渲染组件之后,同时是下次执行上面setInterval之前调用</span> <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> document<span class="token punctuation">.</span>title <span class="token operator">=</span> <span class="token string">"componentWillUnmount"</span><span class="token punctuation">;</span> <span class="token function">clearInterval</span><span class="token punctuation">(</span>timer<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> Count<span class="token punctuation">:</span> <span class="token punctuation">{ </span>count<span class="token punctuation">}</span> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">clearInterval</span><span class="token punctuation">(</span>timer<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span>clear<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>我们使用 useEffect 重写了上面的例子,<strong>useEffect 第一个参数接收一个函数,可以用来做一些副作用比如异步请求,修改外部参数等行为,而第二个参数称之为dependencies,是一个数组,如果数组中的值变化才会触发 执行useEffect 第一个参数中的函数。返回值(如果有)则在组件销毁或者调用函数前调用</strong>。</p> <ul> <li>1.比如第一个 useEffect 中,理解起来就是一旦 count 值发生改变,则修改 documen.title 值;</li> <li>2.而第二个 useEffect 中传递了一个空数组[],这种情况下只有在组件初始化或销毁的时候才会触发,用来代替 componentDidMount 和 componentWillUnmount,慎用;</li> <li> <ol> <li>还有另外一个情况,就是不传递第二个参数,也就是useEffect只接收了第一个函数参数,代表不监听任何参数变化。每次渲染DOM之后,都会执行useEffect中的函数。</li> </ol> </li> </ul> <p>基于这个强大 Hooks,我们可以模拟封装出其他生命周期函数,比如 componentDidUpdate 代码十分简单</p> <pre><code class="prism language-js"><span class="token keyword">function</span> <span class="token function">useUpdate</span><span class="token punctuation">(</span>fn<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token comment">// useRef 创建一个引用</span> <span class="token keyword">const</span> mounting <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">if</span> <span class="token punctuation">(</span>mounting<span class="token punctuation">.</span>current<span class="token punctuation">)</span> <span class="token punctuation">{ </span> mounting<span class="token punctuation">.</span>current <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{ </span> <span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>现在我们有了 useState 管理状态,useEffect 处理副作用,异步逻辑,学会这两招足以应对大部分类组件的使用场景。</p> <h2>3、useContext 减少组件层级</h2> <p>上面介绍了 useState、useEffect 这两个最基本的 API,接下来介绍的 useContext 是 React 帮你封装好的,用来处理多层级传递数据的方式,在以前组件树种,跨层级祖先组件想要给孙子组件传递数据的时候,除了一层层 props 往下透传之外,我们还可以使用 React Context API 来帮我们做这件事,举个简单的例子:</p> <pre><code class="prism language-js"><span class="token keyword">const</span> <span class="token punctuation">{ </span> Provider<span class="token punctuation">,</span> Consumer <span class="token punctuation">}</span> <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">createContext</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">Bar</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token operator"><</span>Consumer<span class="token operator">></span><span class="token punctuation">{ </span>color <span class="token operator">=></span> <span class="token operator"><</span>div<span class="token operator">></span><span class="token punctuation">{ </span>color<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>Consumer<span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">Foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token operator"><</span>Bar <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>Provider value<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token string">"grey"</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Foo <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Provider<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>通过 React createContext 的语法,在 APP 组件中可以跨过 Foo 组件给 Bar 传递数据。而在 React Hooks 中,我们可以使用 useContext 进行改造。</p> <pre><code class="prism language-js"><span class="token keyword">const</span> colorContext <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">createContext</span><span class="token punctuation">(</span><span class="token string">"gray"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">Bar</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> color <span class="token operator">=</span> <span class="token function">useContext</span><span class="token punctuation">(</span>colorContext<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token operator"><</span>div<span class="token operator">></span><span class="token punctuation">{ </span>color<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">Foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token operator"><</span>Bar <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>colorContext<span class="token punctuation">.</span>Provider value<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token string">"red"</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>Foo <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>colorContext<span class="token punctuation">.</span>Provider<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>传递给 useContext 的是 context 而不是 consumer,返回值即是想要透传的数据了。用法很简单,使用 useContext 可以解决 Consumer 多状态嵌套的问题。</p> <pre><code class="prism language-js"><span class="token keyword">function</span> <span class="token function">HeaderBar</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>CurrentUser<span class="token punctuation">.</span>Consumer<span class="token operator">></span> <span class="token punctuation">{ </span>user <span class="token operator">=></span> <span class="token operator"><</span>Notifications<span class="token punctuation">.</span>Consumer<span class="token operator">></span> <span class="token punctuation">{ </span>notifications <span class="token operator">=></span> <span class="token operator"><</span>header<span class="token operator">></span> Welcome back<span class="token punctuation">,</span> <span class="token punctuation">{ </span>user<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token operator">!</span> You have <span class="token punctuation">{ </span>notifications<span class="token punctuation">.</span>length<span class="token punctuation">}</span> notifications<span class="token punctuation">.</span> <span class="token operator"><</span><span class="token operator">/</span>header<span class="token operator">></span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span>CurrentUser<span class="token punctuation">.</span>Consumer<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>而使用 useContext 则变得十分简洁,可读性更强且不会增加组件树深度。</p> <pre><code class="prism language-js"><span class="token keyword">function</span> <span class="token function">HeaderBar</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token function">useContext</span><span class="token punctuation">(</span>CurrentUser<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> notifications <span class="token operator">=</span> <span class="token function">useContext</span><span class="token punctuation">(</span>Notifications<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>header<span class="token operator">></span> Welcome back<span class="token punctuation">,</span> <span class="token punctuation">{ </span>user<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token operator">!</span> You have <span class="token punctuation">{ </span>notifications<span class="token punctuation">.</span>length<span class="token punctuation">}</span> notifications<span class="token punctuation">.</span> <span class="token operator"><</span><span class="token operator">/</span>header<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <h2>4、useReducer</h2> <p>useReducer 这个 Hooks 在使用上几乎跟 Redux/React-Redux 一模一样,唯一缺少的就是无法使用 redux 提供的中间件。我们将上述的计时器组件改写为 useReducer,</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> useReducer <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">const</span> initialState <span class="token operator">=</span> <span class="token punctuation">{ </span> count<span class="token punctuation">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">reducer</span><span class="token punctuation">(</span>state<span class="token punctuation">,</span> action<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">switch</span> <span class="token punctuation">(</span>action<span class="token punctuation">.</span>type<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">case</span> <span class="token string">"increment"</span><span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token punctuation">{ </span> count<span class="token punctuation">:</span> state<span class="token punctuation">.</span>count <span class="token operator">+</span> action<span class="token punctuation">.</span>payload <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token string">"decrement"</span><span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token punctuation">{ </span> count<span class="token punctuation">:</span> state<span class="token punctuation">.</span>count <span class="token operator">-</span> action<span class="token punctuation">.</span>payload <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">default</span><span class="token punctuation">:</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> <span class="token punctuation">[</span>state<span class="token punctuation">,</span> dispatch<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useReducer</span><span class="token punctuation">(</span>reducer<span class="token punctuation">,</span> initialState<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> Count<span class="token punctuation">:</span> <span class="token punctuation">{ </span>state<span class="token punctuation">.</span>count<span class="token punctuation">}</span> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> type<span class="token punctuation">:</span> <span class="token string">"increment"</span><span class="token punctuation">,</span> payload<span class="token punctuation">:</span> <span class="token number">5</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator">+</span> <span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> type<span class="token punctuation">:</span> <span class="token string">"decrement"</span><span class="token punctuation">,</span> payload<span class="token punctuation">:</span> <span class="token number">5</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator">-</span> <span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>用法跟 Redux 基本上是一致的,用法也很简单,算是提供一个 mini 的 Redux 版本。</p> <h2>5、useCallback 记忆函数</h2> <p>在类组件中,我们经常犯下面这样的错误:</p> <pre><code class="prism language-js"><span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token punctuation">{ </span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>SomeComponent style<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">{ </span> fontSize<span class="token punctuation">:</span> <span class="token number">14</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> doSomething<span class="token operator">=</span><span class="token punctuation">{ </span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'do something'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <p>这样写有什么坏处呢?一旦 App 组件的 props 或者状态改变了就会触发重渲染,即使跟 SomeComponent 组件不相关,<strong>由于每次 render 都会产生新的 style 和 doSomething(因为重新render前后, style 和 doSomething分别指向了不同的引用)</strong>,所以会导致 SomeComponent 重新渲染,倘若 SomeComponent 是一个大型的组件树,这样的 Virtual Dom 的比较显然是很浪费的,解决的办法也很简单,将参数抽离成变量。</p> <pre><code class="prism language-js"><span class="token keyword">const</span> fontSizeStyle <span class="token operator">=</span> <span class="token punctuation">{ </span> fontSize<span class="token punctuation">:</span> <span class="token number">14</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token punctuation">{ </span> <span class="token function-variable function">doSomething</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'do something'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>SomeComponent style<span class="token operator">=</span><span class="token punctuation">{ </span>fontSizeStyle<span class="token punctuation">}</span> doSomething<span class="token operator">=</span><span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span>doSomething <span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <p>在类组件中,我们还可以通过 this 这个对象来存储函数,而在函数组件中没办法进行挂载了。所以函数组件在每次渲染的时候如果有传递函数的话都会重渲染子组件。</p> <pre><code class="prism language-js"><span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> <span class="token function-variable function">handleClick</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Click happened'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token operator"><</span>SomeComponent onClick<span class="token operator">=</span><span class="token punctuation">{ </span>handleClick<span class="token punctuation">}</span><span class="token operator">></span>Click Me<span class="token operator"><</span><span class="token operator">/</span>SomeComponent<span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <blockquote> <p>这里多说一句,一版把<strong>函数式组件理解为class组件render函数的语法糖</strong>,所以每次重新渲染的时候,函数式组件内部所有的代码都会重新执行一遍。所以上述代码中每次render,handleClick都会是一个新的引用,所以也就是说传递给SomeComponent组件的props.onClick一直在变(因为每次都是一个新的引用),所以才会说这种情况下,函数组件在每次渲染的时候如果有传递函数的话都会重渲染子组件。</p> </blockquote> <p>而有了 useCallback 就不一样了,你可以通过 useCallback 获得一个记忆后的函数。</p> <pre><code class="prism language-js"><span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> memoizedHandleClick <span class="token operator">=</span> <span class="token function">useCallback</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Click happened'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 空数组代表无论什么情况下该函数都不会发生改变</span> <span class="token keyword">return</span> <span class="token operator"><</span>SomeComponent onClick<span class="token operator">=</span><span class="token punctuation">{ </span>memoizedHandleClick<span class="token punctuation">}</span><span class="token operator">></span>Click Me<span class="token operator"><</span><span class="token operator">/</span>SomeComponent<span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>老规矩,第二个参数传入一个数组,数组中的每一项一旦值或者引用发生改变,useCallback 就会重新返回一个新的记忆函数提供给后面进行渲染。</p> <p>这样只要子组件继承了 PureComponent 或者使用 React.memo 就可以有效避免不必要的 VDOM 渲染。</p> <h2>6、useMemo 记忆组件</h2> <p>useCallback 的功能完全可以由 useMemo 所取代,如果你想通过使用 useMemo 返回一个记忆函数也是完全可以的。</p> <pre><code class="prism language-js"><span class="token function">useCallback</span><span class="token punctuation">(</span>fn<span class="token punctuation">,</span> inputs<span class="token punctuation">)</span> is equivalent to <span class="token function">useMemo</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> fn<span class="token punctuation">,</span> inputs<span class="token punctuation">)</span><span class="token punctuation">.</span> </code></pre> <p>所以前面使用 useCallback 的例子可以使用 useMemo 进行改写:</p> <pre><code class="prism language-js"><span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> memoizedHandleClick <span class="token operator">=</span> <span class="token function">useMemo</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Click happened'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 空数组代表无论什么情况下该函数都不会发生改变</span> <span class="token keyword">return</span> <span class="token operator"><</span>SomeComponent onClick<span class="token operator">=</span><span class="token punctuation">{ </span>memoizedHandleClick<span class="token punctuation">}</span><span class="token operator">></span>Click Me<span class="token operator"><</span><span class="token operator">/</span>SomeComponent<span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>唯一的区别是:**useCallback 不会执行第一个参数函数,而是将它返回给你,而 useMemo 会执行第一个函数并且将函数执行结果返回给你。**所以在前面的例子中,可以返回 handleClick 来达到存储函数的目的。</p> <p>所以 useCallback 常用记忆事件函数,生成记忆后的事件函数并传递给子组件使用。而 useMemo 更适合经过函数计算得到一个确定的值,比如记忆组件。</p> <pre><code class="prism language-js"><span class="token keyword">function</span> <span class="token function">Parent</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> a<span class="token punctuation">,</span> b <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token comment">// Only re-rendered if `a` changes:</span> <span class="token keyword">const</span> child1 <span class="token operator">=</span> <span class="token function">useMemo</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator"><</span>Child1 a<span class="token operator">=</span><span class="token punctuation">{ </span>a<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">,</span> <span class="token punctuation">[</span>a<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Only re-rendered if `b` changes:</span> <span class="token keyword">const</span> child2 <span class="token operator">=</span> <span class="token function">useMemo</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator"><</span>Child2 b<span class="token operator">=</span><span class="token punctuation">{ </span>b<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">,</span> <span class="token punctuation">[</span>b<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token punctuation">{ </span>child1<span class="token punctuation">}</span> <span class="token punctuation">{ </span>child2<span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre> <p>当 a/b 改变时,child1/child2 才会重新渲染。从例子可以看出来,只有在第二个参数数组的值发生变化时,才会触发子组件的更新。</p> <h2>7、useRef 保存引用值</h2> <p>useRef 跟 createRef 类似,都可以用来生成对 DOM 对象的引用,看个简单的例子:</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> useState<span class="token punctuation">,</span> useRef <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">let</span> <span class="token punctuation">[</span>name<span class="token punctuation">,</span> setName<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">"Nate"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> nameRef <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">submitButton</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token function">setName</span><span class="token punctuation">(</span>nameRef<span class="token punctuation">.</span>current<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div className<span class="token operator">=</span><span class="token string">"App"</span><span class="token operator">></span> <span class="token operator"><</span>p<span class="token operator">></span><span class="token punctuation">{ </span>name<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>input ref<span class="token operator">=</span><span class="token punctuation">{ </span>nameRef<span class="token punctuation">}</span> type<span class="token operator">=</span><span class="token string">"text"</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span>button type<span class="token operator">=</span><span class="token string">"button"</span> onClick<span class="token operator">=</span><span class="token punctuation">{ </span>submitButton<span class="token punctuation">}</span><span class="token operator">></span> Submit <span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>useRef 返回的值传递给组件或者 DOM 的 ref 属性,就可以通过 ref.current 值<strong>访问组件或真实的 DOM 节点,重点是组件也是可以访问到的</strong>,从而可以对 DOM 进行一些操作,比如监听事件等等。</p> <p>当然 useRef 远比你想象中的功能更加强大,useRef 的功能有点像类属性,或者说您想要在组件中记录一些值,并且这些值在稍后可以更改。</p> <p>利用 useRef 就可以绕过 Capture Value 的特性。可以认为 ref 在所有 Render 过程中保持着唯一引用,因此所有对 ref 的赋值或取值,拿到的都只有一个最终状态,而不会在每个 Render 间存在隔离。</p> <p>React Hooks 中存在 Capture Value 的特性:</p> <pre><code class="prism language-js"><span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> <span class="token punctuation">[</span>count<span class="token punctuation">,</span> setCount<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"count: "</span> <span class="token operator">+</span> count<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">3000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>count<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>p<span class="token operator">></span>You clicked <span class="token punctuation">{ </span>count<span class="token punctuation">}</span> times<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setCount</span><span class="token punctuation">(</span>count <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span>增加 count<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setCount</span><span class="token punctuation">(</span>count <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span>减少 count<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>先点击增加button,后点击减少button,3秒后先alert 1,后alert 0,而不是alert两次0。这就是所谓的 capture value 的特性。而在<strong>类组件</strong>中 3 秒后输出的就是修改后的值,因为这时候 <strong>message 是挂载在 this 变量上,它保留的是一个引用值</strong>,对 this 属性的访问都会获取到最新的值。讲到这里你应该就明白了,useRef 创建一个引用,就可以有效规避 React Hooks 中 Capture Value 特性。</p> <pre><code class="prism language-js"><span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> count <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">showCount</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"count: "</span> <span class="token operator">+</span> count<span class="token punctuation">.</span>current<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">handleClick</span> <span class="token operator">=</span> number <span class="token operator">=></span> <span class="token punctuation">{ </span> count<span class="token punctuation">.</span>current <span class="token operator">=</span> count<span class="token punctuation">.</span>current <span class="token operator">+</span> number<span class="token punctuation">;</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span>showCount<span class="token punctuation">,</span> <span class="token number">3000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>p<span class="token operator">></span>You clicked <span class="token punctuation">{ </span>count<span class="token punctuation">.</span>current<span class="token punctuation">}</span> times<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">handleClick</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span>增加 count<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{ </span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">handleClick</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span>减少 count<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>只要将赋值与取值的对象变成 useRef,而不是 useState,就可以躲过 capture value 特性,在 3 秒后得到最新的值。</p> <h2>8、useImperativeHandle 透传 Ref</h2> <p>通过 useImperativeHandle 用于让父组件获取子组件内的索引</p> <pre><code class="prism language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{ </span> useRef<span class="token punctuation">,</span> useEffect<span class="token punctuation">,</span> useImperativeHandle<span class="token punctuation">,</span> forwardRef <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">ChildInputComponent</span><span class="token punctuation">(</span>props<span class="token punctuation">,</span> ref<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> inputRef <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">useImperativeHandle</span><span class="token punctuation">(</span>ref<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> inputRef<span class="token punctuation">.</span>current<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token operator"><</span>input type<span class="token operator">=</span><span class="token string">"text"</span> name<span class="token operator">=</span><span class="token string">"child input"</span> ref<span class="token operator">=</span><span class="token punctuation">{ </span>inputRef<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> ChildInput <span class="token operator">=</span> <span class="token function">forwardRef</span><span class="token punctuation">(</span>ChildInputComponent<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> inputRef <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> inputRef<span class="token punctuation">.</span>current<span class="token punctuation">.</span><span class="token function">focus</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>ChildInput ref<span class="token operator">=</span><span class="token punctuation">{ </span>inputRef<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>通过这种方式,App 组件可以获得子组件的 input 的 DOM 节点。</p> <h2>9、useLayoutEffect 同步执行副作用</h2> <p>大部分情况下,使用 useEffect 就可以帮我们处理组件的副作用,但是如果想要同步调用一些副作用,比如对 DOM 的操作,就需要使用 useLayoutEffect,useLayoutEffect 中的副作用会在 DOM 更新之后同步执行。</p> <pre><code class="prism language-js"><span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> <span class="token punctuation">[</span>width<span class="token punctuation">,</span> setWidth<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">useLayoutEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token keyword">const</span> title <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"#title"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> titleWidth <span class="token operator">=</span> title<span class="token punctuation">.</span><span class="token function">getBoundingClientRect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>width<span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"useLayoutEffect"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>width <span class="token operator">!==</span> titleWidth<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token function">setWidth</span><span class="token punctuation">(</span>titleWidth<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"useEffect"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>h1 id<span class="token operator">=</span><span class="token string">"title"</span><span class="token operator">></span>hello<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span>h2<span class="token operator">></span><span class="token punctuation">{ </span>width<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>h2<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>在上面的例子中,useLayoutEffect 会在 render,DOM 更新之后同步触发函数,会优于 useEffect 异步触发函数。</p> <h3>(1) useEffect和useLayoutEffect有什么区别?</h3> <p><strong>简单来说就是调用时机不同,<code>useLayoutEffect</code>和原来<code>componentDidMount</code>&<code>componentDidUpdate</code>一致,在react完成DOM更新后马上</strong>同步<strong>调用的代码,会阻塞页面渲染。而<code>useEffect</code>是会在整个页面渲染完才会调用的代码。</strong></p> <p>官方建议优先使用<code>useEffect</code></p> <blockquote> <p>However, <strong>we recommend starting with useEffect first</strong> and only trying useLayoutEffect if that causes a problem.</p> </blockquote> <p>在实际使用时如果想避免<strong>页面抖动</strong>(在<code>useEffect</code>里修改DOM很有可能出现)的话,可以把需要操作DOM的代码放在<code>useLayoutEffect</code>里。关于使用<code>useEffect</code>导致页面抖动。</p> <p>不过<code>useLayoutEffect</code>在服务端渲染时会出现一个warning,要消除的话得用<code>useEffect</code>代替或者推迟渲染时机。</p> <h1>二十、Mobx</h1> <p>Mobx是一个功能强大,上手非常容易的状态管理工具。redux的作者也曾经向大家推荐过它,在不少情况下可以使用Mobx来替代掉redux。</p> <p><a href="http://img.e-com-net.com/image/info8/f4ef359dd1ec43e2a362038b820a587e.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/f4ef359dd1ec43e2a362038b820a587e.jpg" alt="2021react复习_第12张图片" width="650" height="223" style="border:1px solid black;"></a></p> <p>这张图来自于官网,把这张图理解清楚了。基本上对于mobx的理解就算入门了。</p> <p>官网有明确的核心概念使用方法,并配有egghead的视频教程。这里就不一一赘述了。</p> <p>要特别注意当使用 <code>mobx-react</code> 时可以定义一个新的生命周期钩子函数 <code>componentWillReact</code>。当组件因为它观察的数据发生了改变,它会安排重新渲染,这个时候 <code>componentWillReact</code> 会被触发。这使得它很容易追溯渲染并找到导致渲染的操作(action)。</p> <ul> <li><code>componentWillReact</code> 不接收参数</li> <li><code>componentWillReact</code> 初始化渲染前不会触发 (使用 <code>componentWillMount</code> 替代)</li> <li><code>componentWillReact</code> 对于 mobx-react@4+, 当接收新的 props 时并在 <code>setState</code> 调用后会触发此钩子</li> <li>要触发<code>componentWillReact</code>必须在render里面用到被观察的变量</li> <li>使用Mobx之后不会触发<code>componentWillReceiveProps</code></li> </ul> <h2>1、搭建环境</h2> <pre><code>mkdir my-app cd my-app npm init -y npm i webpack webpack-cli webpack-dev-server -D npm i html-webpack-plugin -D npm i babel-loader @babel/core @babel/preset-env -D npm i @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties -D npm i @babel/plugin-transform-runtime -D npm i @babel/runtime -S npm i mobx -S mkdir src mkdir dist touch index.html touch src/index.js touch webpack.config.js </code></pre> <p>编写webpack.config.js</p> <pre><code class="prism language-js"><span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'path'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> HtmlWebpackPlugin <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'html-webpack-plugin'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{ </span> mode<span class="token punctuation">:</span> <span class="token string">'development'</span><span class="token punctuation">,</span> entry<span class="token punctuation">:</span> path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'src/index.js'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> output<span class="token punctuation">:</span> <span class="token punctuation">{ </span> path<span class="token punctuation">:</span> path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'dist'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> filename<span class="token punctuation">:</span> <span class="token string">'main.js'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> module<span class="token punctuation">:</span> <span class="token punctuation">{ </span> rules<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{ </span> test<span class="token punctuation">:</span> <span class="token regex">/\.js$/</span><span class="token punctuation">,</span> exclude<span class="token punctuation">:</span> <span class="token regex">/node_modules/</span><span class="token punctuation">,</span> use<span class="token punctuation">:</span> <span class="token punctuation">{ </span> loader<span class="token punctuation">:</span> <span class="token string">'babel-loader'</span><span class="token punctuation">,</span> options<span class="token punctuation">:</span> <span class="token punctuation">{ </span> presets<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'@babel/preset-env'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> plugins<span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token comment">//支持装饰器</span> <span class="token punctuation">[</span><span class="token string">"@babel/plugin-proposal-decorators"</span><span class="token punctuation">,</span> <span class="token punctuation">{ </span> <span class="token string">"legacy"</span><span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">"@babel/plugin-proposal-class-properties"</span><span class="token punctuation">,</span> <span class="token punctuation">{ </span> <span class="token string">"loose"</span> <span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'@babel/plugin-transform-runtime'</span><span class="token punctuation">]</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> plugins<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token keyword">new</span> <span class="token class-name">HtmlWebpackPlugin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span> devtool<span class="token punctuation">:</span> <span class="token string">'inline-source-map'</span> <span class="token punctuation">}</span> </code></pre> <p>编写index.html</p> <pre><code class="prism language-html"><span class="token doctype"><!DOCTYPE html></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>UTF-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1.0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Document<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span> </code></pre> <h2>2、Mobx 入门</h2> <h3>(1) observable可观察的状态</h3> <ul> <li>map</li> </ul> <pre><code class="prism language-js"><span class="token keyword">import</span> <span class="token punctuation">{ </span>observable<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'mobx'</span> <span class="token comment">// 声明</span> <span class="token keyword">const</span> map <span class="token operator">=</span> observable<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">{ </span>a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 设置</span> map<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token string">'a'</span><span class="token punctuation">,</span> <span class="token number">11</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 获取</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>map<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">'a'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>map<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">'b'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 删除</span> map<span class="token punctuation">.</span><span class="token keyword">delete</span><span class="token punctuation">(</span><span class="token string">'a'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>map<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">'a'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 判断是否存在属性</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>map<span class="token punctuation">.</span><span class="token function">has</span><span class="token punctuation">(</span><span class="token string">'a'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <ul> <li>object</li> </ul> <pre><code class="prism language-js"><span class="token keyword">import</span> <span class="token punctuation">{ </span>observable<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'mobx'</span> <span class="token comment">// 声明</span> <span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token function">observable</span><span class="token punctuation">(</span><span class="token punctuation">{ </span>a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 修改</span> obj<span class="token punctuation">.</span>a <span class="token operator">=</span> <span class="token number">11</span><span class="token punctuation">;</span> <span class="token comment">// 访问</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj<span class="token punctuation">.</span>a<span class="token punctuation">,</span> obj<span class="token punctuation">.</span>b<span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <ul> <li>array</li> </ul> <pre><code class="prism language-js"><span class="token keyword">import</span> <span class="token punctuation">{ </span>observable<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'mobx'</span> <span class="token keyword">const</span> arr <span class="token operator">=</span> <span class="token function">observable</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'a'</span><span class="token punctuation">,</span> <span class="token string">'b'</span><span class="token punctuation">,</span> <span class="token string">'c'</span><span class="token punctuation">,</span> <span class="token string">'d'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 访问</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>arr<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> arr<span class="token punctuation">[</span><span class="token number">10</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 操作</span> arr<span class="token punctuation">.</span><span class="token function">pop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> arr<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">'e'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <ul> <li>基础类型</li> </ul> <pre><code class="prism language-js"><span class="token keyword">import</span> <span class="token punctuation">{ </span>observable<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'mobx'</span><span class="token operator">/</span> <span class="token keyword">const</span> num <span class="token operator">=</span> observable<span class="token punctuation">.</span><span class="token function">box</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> str <span class="token operator">=</span> observable<span class="token punctuation">.</span><span class="token function">box</span><span class="token punctuation">(</span><span class="token string">'hello'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> bool <span class="token operator">=</span> observable<span class="token punctuation">.</span><span class="token function">box</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 获得值</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>num<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> str<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> bool<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 修改值</span> num<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span> str<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token string">'hi'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> bool<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>num<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> str<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> bool<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <h3>(2) observable装饰器</h3> <pre><code class="prism language-js"><span class="token keyword">import</span> <span class="token punctuation">{ </span>observable<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'mobx'</span> <span class="token comment">// observable这个函数可以识别当成普通函数调用还是装饰器调用</span> <span class="token comment">// 如果是装饰器,会自动识别数据类型,使用不同的包装转换方案。</span> <span class="token keyword">class</span> <span class="token class-name">Store</span><span class="token punctuation">{ </span> @observable arr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> @observable obj <span class="token operator">=</span> <span class="token punctuation">{ </span>a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">}</span><span class="token punctuation">;</span> @observable map <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Map</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> @observable str <span class="token operator">=</span> <span class="token string">'hello'</span><span class="token punctuation">;</span> @observable num <span class="token operator">=</span> <span class="token number">123</span><span class="token punctuation">;</span> @observable bool <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> store <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Store</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>store<span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>store<span class="token punctuation">.</span>obj<span class="token punctuation">.</span>a<span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <p>注意:vscode编译器中,js文件使用装饰器会报红。解决方式:</p> <p>在根目录编写jsconfig.json</p> <pre><code class="prism language-json"><span class="token punctuation">{ </span> <span class="token string">"compilerOptions"</span><span class="token punctuation">:</span> <span class="token punctuation">{ </span> <span class="token string">"module"</span><span class="token punctuation">:</span> <span class="token string">"commonjs"</span><span class="token punctuation">,</span> <span class="token string">"target"</span><span class="token punctuation">:</span> <span class="token string">"es6"</span><span class="token punctuation">,</span> <span class="token string">"experimentalDecorators"</span><span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">"include"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"src/**/*"</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> </code></pre> <h3>(3) 对 observables 作出响应</h3> <ul> <li>基础代码:</li> </ul> <pre><code class="prism language-js"><span class="token keyword">import</span> <span class="token punctuation">{ </span>observable<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'mobx'</span> <span class="token keyword">class</span> <span class="token class-name">Store</span><span class="token punctuation">{ </span> @observable arr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> @observable obj <span class="token operator">=</span> <span class="token punctuation">{ </span>a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">}</span><span class="token punctuation">;</span> @observable map <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Map</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> @observable str <span class="token operator">=</span> <span class="token string">'hello'</span><span class="token punctuation">;</span> @observable num <span class="token operator">=</span> <span class="token number">123</span><span class="token punctuation">;</span> @observable bool <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> store <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Store</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <ul> <li>computed</li> </ul> <p>计算值是可以根据现有的状态或其它计算值衍生出的值, 跟vue中的computed非常相似。</p> <pre><code class="prism language-js"><span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span>store<span class="token punctuation">.</span>str <span class="token operator">+</span> store<span class="token punctuation">.</span>num<span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 监听数据的变化</span> result<span class="token punctuation">.</span><span class="token function">observe</span><span class="token punctuation">(</span><span class="token punctuation">(</span>change<span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{ </span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'result:'</span><span class="token punctuation">,</span> change<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment">//两次对store属性的修改都会引起result的变化</span> store<span class="token punctuation">.</span>str <span class="token operator">=</span> <span class="token string">'world'</span><span class="token punctuation">;</span> store<span class="token punctuation">.</span>num <span class="token operator">=</span> <span class="token number">220</span><span class="token punctuation">;</span> </code></pre> <p>computed可作为装饰器, 将result的计算添加到类中:</p> <pre><code class="prism language-js"><span class="token keyword">class</span> <span class="token class-name">Store</span><span class="token punctuation">{ </span> @observable arr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> @observable obj <span class="token operator">=</span> <span class="token punctuation">{ </span>a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">}</span><span class="token punctuation">;</span> @observable map <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Map</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> @observable str <span class="token operator">=</span> <span class="token string">'hello'</span><span class="token punctuation">;</span> @observable num <span class="token operator">=</span> <span class="token number">123</span><span class="token punctuation">;</span> @observable bool <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> @computed <span class="token keyword">get</span> <span class="token function">result</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>str <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>num<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <ul> <li>autorun</li> </ul> <p>当你想创建一个响应式函数,而该函数本身永远不会有观察者时,可以使用 <code>mobx.autorun</code></p> <p>所提供的函数总是立即被触发一次,然后每次它的依赖关系改变时会再次被触发。</p> <p>经验法则:如果你有一个函数应该自动运行,但不会产生一个新的值,请使用<code>autorun</code>。 其余情况都应该使用 <code>computed</code>。</p> <pre><code class="prism language-js"><span class="token comment">//aotu会立即触发一次</span> <span class="token function">autorun</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{ </span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>store<span class="token punctuation">.</span>str <span class="token operator">+</span> store<span class="token punctuation">.</span>num<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token function">autorun</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{ </span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>store<span class="token punctuation">.</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment">//两次修改都会引起autorun执行</span> store<span class="token punctuation">.</span>num <span class="token operator">=</span> <span class="token number">220</span><span class="token punctuation">;</span> store<span class="token punctuation">.</span>str <span class="token operator">=</span> <span class="token string">'world'</span><span class="token punctuation">;</span> </code></pre> <ul> <li>when</li> </ul> <pre><code class="prism language-js"><span class="token function">when</span><span class="token punctuation">(</span>predicate<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> boolean<span class="token punctuation">,</span> effect<span class="token operator">?</span><span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">void</span><span class="token punctuation">,</span> options<span class="token operator">?</span><span class="token punctuation">)</span> </code></pre> <p><code>when</code> 观察并运行给定的 <code>predicate</code>,直到返回true。 一旦返回 true,给定的 <code>effect</code> 就会被执行,然后 autorunner(自动运行程序) 会被清理。 该函数返回一个清理器以提前取消自动运行程序。</p> <p>对于以响应式方式来进行处理或者取消,此函数非常有用。</p> <pre><code class="prism language-js"><span class="token function">when</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span>store<span class="token punctuation">.</span>bool<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{ </span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'when function run.....'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> store<span class="token punctuation">.</span>bool <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> </code></pre> <ul> <li>reaction</li> </ul> <p>用法: <code>reaction(() => data, (data, reaction) => { sideEffect }, options?)</code>。</p> <p><code>autorun</code> 的变种,对于如何追踪 observable 赋予了更细粒度的控制。 它接收两个函数参数,第一个(<em>数据</em> 函数)是用来追踪并返回数据作为第二个函数(<em>效果</em> 函数)的输入。 不同于 <code>autorun</code> 的是当创建时<em>效果</em> 函数不会直接运行,只有在数据表达式首次返回一个新值后才会运行。 在执行 <em>效果</em> 函数时访问的任何 observable 都不会被追踪。</p> <pre><code class="prism language-js"><span class="token comment">// reaction</span> <span class="token function">reaction</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">[</span>store<span class="token punctuation">.</span>str<span class="token punctuation">,</span> store<span class="token punctuation">.</span>num<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>arr<span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{ </span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>arr<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment">//只要[store.str, store.num]中任意一值发生变化,reaction第二个函数都会执行</span> store<span class="token punctuation">.</span>num <span class="token operator">=</span> <span class="token number">220</span><span class="token punctuation">;</span> store<span class="token punctuation">.</span>str <span class="token operator">=</span> <span class="token string">'world'</span><span class="token punctuation">;</span> </code></pre> <h3>(4) 改变 observables状态</h3> <ul> <li>action</li> </ul> <p>接上面案例,添加action到类中:</p> <pre><code class="prism language-js"><span class="token keyword">class</span> <span class="token class-name">Store</span><span class="token punctuation">{ </span> @observable arr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> @observable obj <span class="token operator">=</span> <span class="token punctuation">{ </span>a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">}</span><span class="token punctuation">;</span> @observable map <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Map</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> @observable str <span class="token operator">=</span> <span class="token string">'hello'</span><span class="token punctuation">;</span> @observable num <span class="token operator">=</span> <span class="token number">123</span><span class="token punctuation">;</span> @observable bool <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> @computed <span class="token keyword">get</span> <span class="token function">result</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>str <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>num<span class="token punctuation">;</span> <span class="token punctuation">}</span> @action <span class="token function">bar</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span>str <span class="token operator">=</span> <span class="token string">'world'</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>num <span class="token operator">=</span> <span class="token number">40</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> store <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Store</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//调用action,只会执行一次</span> store<span class="token punctuation">.</span><span class="token function">bar</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <ul> <li>action.bound</li> </ul> <p><code>action.bound</code> 可以用来自动地将动作绑定到目标对象。</p> <pre><code class="prism language-js"><span class="token keyword">class</span> <span class="token class-name">Store</span><span class="token punctuation">{ </span> @observable arr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> @observable obj <span class="token operator">=</span> <span class="token punctuation">{ </span>a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">}</span><span class="token punctuation">;</span> @observable map <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Map</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> @observable str <span class="token operator">=</span> <span class="token string">'hello'</span><span class="token punctuation">;</span> @observable num <span class="token operator">=</span> <span class="token number">123</span><span class="token punctuation">;</span> @observable bool <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> @computed <span class="token keyword">get</span> <span class="token function">result</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{ </span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>str <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>num<span class="token punctuation">;</span> <span class="token punctuation">}</span> @action <span class="token function">bar</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span>str <span class="token operator">=</span> <span class="token string">'world'</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>num <span class="token operator">=</span> <span class="token number">40</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//this 永远都是正确的</span> @action<span class="token punctuation">.</span>bound <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{ </span> <span class="token keyword">this</span><span class="token punctuation">.</span>str <span class="token operator">=</span> <span class="token string">'world'</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>num <span class="token operator">=</span> <span class="token number">40</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> store <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Store</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setInterval</span><span class="token punctuation">(</span>store<span class="token punctuation">.</span>foo<span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span> </code></pre> <ul> <li>runInAction</li> </ul> <p><code>action</code> 只能影响正在运行的函数,而无法影响当前函数调用的异步操作。如果你使用async function来处理业务,那么我们可以使用 <code>runInAction</code> 这个API来解决这个问题。</p> <pre><code class="prism language-js">@action <span class="token keyword">async</span> <span class="token function">fzz</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">await</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span>resolve<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">{ </span> num<span class="token punctuation">:</span> <span class="token number">220</span><span class="token punctuation">,</span> str<span class="token punctuation">:</span> <span class="token string">'world'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token function">runInAction</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{ </span> store<span class="token punctuation">.</span>num <span class="token operator">=</span> <span class="token number">220</span> store<span class="token punctuation">.</span>str <span class="token operator">=</span> <span class="token string">'world'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre> <h2>3、应用</h2> <h3>(1) 在react中使用mobx</h3> <p>在react中使用mobx,需要借助mobx-react。</p> <p>它的功能相当于在react中使用redux,需要借助react-redux。</p> <p>首先来搭建环境:</p> <pre><code>create-react-app react-app cd react-app npm run eject npm i @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties -D npm i mobx mobx-react -S </code></pre> <p>修改package.json中babel的配置:</p> <pre><code class="prism language-json"> <span class="token string">"babel"</span><span class="token punctuation">:</span> <span class="token punctuation">{ </span> <span class="token string">"presets"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token string">"react-app"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">"plugins"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">[</span> <span class="token string">"@babel/plugin-proposal-decorators"</span><span class="token punctuation">,</span> <span class="token punctuation">{ </span> <span class="token string">"legacy"</span><span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token string">"@babel/plugin-proposal-class-properties"</span><span class="token punctuation">,</span> <span class="token punctuation">{ </span> <span class="token string">"loose"</span><span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> </code></pre> <p>注意:vscode编译器中,js文件使用装饰器会报红。解决方式:</p> <p>在根目录编写写jsconfig.json</p> <pre><code class="prism language-json"><span class="token punctuation">{ </span> <span class="token string">"compilerOptions"</span><span class="token punctuation">:</span> <span class="token punctuation">{ </span> <span class="token string">"module"</span><span class="token punctuation">:</span> <span class="token string">"commonjs"</span><span class="token punctuation">,</span> <span class="token string">"target"</span><span class="token punctuation">:</span> <span class="token string">"es6"</span><span class="token punctuation">,</span> <span class="token string">"experimentalDecorators"</span><span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">"include"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"src/**/*"</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> </code></pre> <p>###(2)项目应用</p> <p><strong>入口文件:</strong></p> <pre><code class="prism language-js"><span class="token keyword">import</span> <span class="token punctuation">{ </span> Provider <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'mobx-react'</span> <span class="token operator"><</span>Provider store<span class="token operator">=</span><span class="token punctuation">{ </span>homeStore<span class="token punctuation">}</span> morestore<span class="token operator">=</span><span class="token punctuation">{ </span>moreStore<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>App<span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>App<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>Provider<span class="token operator">></span> </code></pre> <p><strong>组件:</strong></p> <pre><code class="prism language-js"><span class="token keyword">import</span> <span class="token punctuation">{ </span> observer<span class="token punctuation">,</span> inject <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'mobx-react'</span> @<span class="token function">inject</span><span class="token punctuation">(</span><span class="token string">'store'</span><span class="token punctuation">)</span> @observer <span class="token keyword">class</span> <span class="token class-name">Swiper</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span><span class="token punctuation">{ </span><span class="token punctuation">}</span> </code></pre> <h1>附加</h1> <h2>一、create-react-app 支持decorators</h2> <pre><code>yarn add @babel/core @babel/plugin-proposal-decorators @babel/preset-env </code></pre> <p><strong>创建 .babelrc</strong></p> <pre><code class="prism language-js"><span class="token punctuation">{ </span> <span class="token string">"presets"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token string">"@babel/preset-env"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">"plugins"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">[</span> <span class="token string">"@babel/plugin-proposal-decorators"</span><span class="token punctuation">,</span> <span class="token punctuation">{ </span> <span class="token string">"legacy"</span><span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> </code></pre> <p><strong>创建config-overrides.js</strong></p> <pre><code class="prism language-js"><span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'path'</span><span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">{ </span> override<span class="token punctuation">,</span> addDecoratorsLegacy <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'customize-cra'</span><span class="token punctuation">)</span> <span class="token keyword">function</span> <span class="token function">resolve</span><span class="token punctuation">(</span>dir<span class="token punctuation">)</span> <span class="token punctuation">{ </span> <span class="token keyword">return</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> dir<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> <span class="token function-variable function">customize</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span>config<span class="token punctuation">,</span> env<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{ </span> config<span class="token punctuation">.</span>resolve<span class="token punctuation">.</span>alias<span class="token punctuation">[</span><span class="token string">'@'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">'src'</span><span class="token punctuation">)</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>env <span class="token operator">===</span> <span class="token string">'production'</span><span class="token punctuation">)</span> <span class="token punctuation">{ </span> config<span class="token punctuation">.</span>externals <span class="token operator">=</span> <span class="token punctuation">{ </span> <span class="token string">'react'</span><span class="token punctuation">:</span> <span class="token string">'React'</span><span class="token punctuation">,</span> <span class="token string">'react-dom'</span><span class="token punctuation">:</span> <span class="token string">'ReactDOM'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> config <span class="token punctuation">}</span><span class="token punctuation">;</span> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token function">override</span><span class="token punctuation">(</span><span class="token function">addDecoratorsLegacy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">customize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> </code></pre> <p><strong>安装依赖</strong></p> <pre><code>yarn add customize-cra react-app-rewired </code></pre> <p><strong>修改package.json</strong></p> <pre><code class="prism language-json"><span class="token operator">...</span> <span class="token string">"scripts"</span><span class="token punctuation">:</span> <span class="token punctuation">{ </span> <span class="token string">"start"</span><span class="token punctuation">:</span> <span class="token string">"react-app-rewired start"</span><span class="token punctuation">,</span> <span class="token string">"build"</span><span class="token punctuation">:</span> <span class="token string">"react-app-rewired build"</span><span class="token punctuation">,</span> <span class="token string">"test"</span><span class="token punctuation">:</span> <span class="token string">"react-app-rewired test"</span><span class="token punctuation">,</span> <span class="token string">"eject"</span><span class="token punctuation">:</span> <span class="token string">"react-app-rewired eject"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token operator">...</span> 的值,请使用<span class="token template-string"><span class="token string">`autorun`</span></span>。 其余情况都应该使用 <span class="token template-string"><span class="token string">`computed`</span></span>。 <span class="token template-string"><span class="token string">``</span></span>`js <span class="token comment">//aotu会立即触发一次</span> <span class="token function">autorun</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{ </span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>store<span class="token punctuation">.</span>str <span class="token operator">+</span> store<span class="token punctuation">.</span>num<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token function">autorun</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{ </span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>store<span class="token punctuation">.</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment">//两次修改都会引起autorun执行</span> store<span class="token punctuation">.</span>num <span class="token operator">=</span> <span class="token number">220</span><span class="token punctuation">;</span> store<span class="token punctuation">.</span>str <span class="token operator">=</span> <span class="token string">'world'</span><span class="token punctuation">;</span> </code></pre> </div> </div> </div> </div> </div> <!--PC和WAP自适应版--> <div id="SOHUCS" sid="1388465378463666176"></div> <script type="text/javascript" src="/views/front/js/chanyan.js"></script> <!-- 文章页-底部 动态广告位 --> <div class="youdao-fixed-ad" id="detail_ad_bottom"></div> </div> <div class="col-md-3"> <div class="row" id="ad"> <!-- 文章页-右侧1 动态广告位 --> <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_1"> </div> </div> <!-- 文章页-右侧2 动态广告位 --> <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_2"></div> </div> <!-- 文章页-右侧3 动态广告位 --> <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_3"></div> </div> </div> </div> </div> </div> </div> <div class="container"> <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(前端)</h4> <div id="paradigm-article-related"> <div class="recommend-post mb30"> <ul class="widget-links"> <li><a href="/article/1883434086782005248.htm" title="多线程在打包工具中的运用" target="_blank">多线程在打包工具中的运用</a> <span class="text-muted"></span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>我们是袋鼠云数栈UED团队,致力于打造优秀的一站式数据中台产品。我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值。本文作者:UED团队现代操作系统都是「多任务」的,也就是操作系统可以「并发」处理多个任务,比如可以在浏览页面的时候同时播放音乐。但是,一般来说我们的PC只有一个物理CPU,那么它是如何做到在只有一个CPU的情况下,并发处理多个任务的呢?我们简单探究一下。前置知识我们先简单熟</div> </li> <li><a href="/article/1883424771681611776.htm" title="web前端10--变化" target="_blank">web前端10--变化</a> <span class="text-muted">Lorcian</span> <a class="tag" taget="_blank" href="/search/css/1.htm">css</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AE%B0/1.htm">笔记</a><a class="tag" taget="_blank" href="/search/html5/1.htm">html5</a> <div>-transform`transform`:允许你通过改变元素的位置、旋转、缩放或倾斜来操作元素。1、rotate()`rotate()`函数旋转元素。语法:`rotate(angle)`,其中`angle`表示旋转的角度。```css.element{transform:rotate(45deg);}```2、scale()`scale()`函数缩放元素的大小。语法:`scale(x,y)`,其</div> </li> <li><a href="/article/1883408253916868608.htm" title="云借阅-图书管理系统" target="_blank">云借阅-图书管理系统</a> <span class="text-muted">夏之目</span> <a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F/1.htm">程序</a><a class="tag" taget="_blank" href="/search/mybatis/1.htm">mybatis</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a> <div>程序设计逻辑简单,适合观摩学习使用。文章目录前言一、开发技术与工具二、功能模块三、运行截图总结前言云借阅图书管理系统主要实现了两大功能模块:用户登录模块和图书管理模块,用户登录模块主要用于实现用户的登录与注销;图书管理模块主要用于管理图书,如新书推荐、图书借阅等。一、开发技术与工具1.开发技术:后端:SSM(Spring、SpringMVC、Mybatis)框架前端:JSP、Ajax、JQuery</div> </li> <li><a href="/article/1883369303605047296.htm" title="Angular 1 深度解析:脏数据检查与 angular 性能优化" target="_blank">Angular 1 深度解析:脏数据检查与 angular 性能优化</a> <span class="text-muted">chouang1992</span> <a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/ui/1.htm">ui</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6/1.htm">前端框架</a><a class="tag" taget="_blank" href="/search/ViewUI/1.htm">ViewUI</a> <div>TL;DR脏检查是一种模型到视图的数据映射机制,由$apply或$digest触发。脏检查的范围是整个页面,不受区域或组件划分影响使用尽量简单的绑定表达式提升脏检查执行速度尽量减少页面上绑定表达式的个数(单次绑定和ng-if)给ng-repeat添加trackby让angular复用已有元素什么是脏数据检查(Dirtychecking)Angular是一个MVVM前端框架,提供了双向数据绑定。所谓</div> </li> <li><a href="/article/1883315324950999040.htm" title="vue 无法 局域网内访问" target="_blank">vue 无法 局域网内访问</a> <span class="text-muted">m0_75101866</span> <a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/1.htm">开发工具</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a> <div>资料Vue项目设置可以局域网访问_vue.js_脚本之家过程上午,前端vue服务能够在局域网内访问,下午就不行了,但是后端服务能够正常访问,本机也能正常访问ip:端口号前端服务判定不是下面的问题:同一局域网下访问vue项目_vue在局域网内访问-CSDN博客然后,关闭防火墙尝试。。-_-!netshadvfirewallfirewalladdrulename="Allow8080"dir=inac</div> </li> <li><a href="/article/1883311792134877184.htm" title="微信小程序部分用户报错ERR_CONNECTION_REFUSED连接被拒绝" target="_blank">微信小程序部分用户报错ERR_CONNECTION_REFUSED连接被拒绝</a> <span class="text-muted">木雷双雄7</span> <a class="tag" taget="_blank" href="/search/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">微信小程序</a><a class="tag" taget="_blank" href="/search/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">微信小程序</a> <div>【问题描述】部分微信小程序用户出现连接被拒绝的错误,报错信息为{"code":0,"message":"{\"errno\":600001,\"errMsg\":\"request:failerrcode:-102cronet_error_code:-102error_msg:net::ERR_CONNECTION_REFUSED\"}"}【问题排查】后端没有错误日志,前端没有js报错,那报错从何</div> </li> <li><a href="/article/1883307627673350144.htm" title="vue 前端显示图片加token_手摸手,带你用vue撸后台 系列二(登录权限篇)" target="_blank">vue 前端显示图片加token_手摸手,带你用vue撸后台 系列二(登录权限篇)</a> <span class="text-muted">weixin_39562579</span> <a class="tag" taget="_blank" href="/search/vue/1.htm">vue</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E6%98%BE%E7%A4%BA%E5%9B%BE%E7%89%87%E5%8A%A0token/1.htm">前端显示图片加token</a><a class="tag" taget="_blank" href="/search/vue%E6%9C%AC%E5%9C%B0%E5%AD%98%E5%82%A8/1.htm">vue本地存储</a><a class="tag" taget="_blank" href="/search/vue%E7%BC%96%E8%BE%91%E9%A1%B5%E9%9D%A2%E5%92%8C%E6%96%B0%E5%A2%9E/1.htm">vue编辑页面和新增</a> <div>完整项目地址:vue-element-adminhttps://github.com/PanJiaChen/vue-element-admin前言拖更有点严重,过了半个月才写了第二篇教程。无奈自己是一个业务猿,每天被我司的产品虐的死去活来,之前又病了一下休息了几天,大家见谅。进入正题,做后台项目区别于做其它的项目,权限验证与安全性是非常重要的,可以说是一个后台项目一开始就必须考虑和搭建的基础核心功</div> </li> <li><a href="/article/1883305733085261824.htm" title="Vite + Vue3 + TS项目配置前置路由守卫" target="_blank">Vite + Vue3 + TS项目配置前置路由守卫</a> <span class="text-muted">洛*璃</span> <a class="tag" taget="_blank" href="/search/Vue.js/1.htm">Vue.js</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/Vue-Router/1.htm">Vue-Router</a><a class="tag" taget="_blank" href="/search/Pinia/1.htm">Pinia</a><a class="tag" taget="_blank" href="/search/typescript/1.htm">typescript</a> <div>在现代前端开发中,使用Vue3和TypeScript的组合是一种流行且高效的开发方式。Vite是一个极速的构建工具,可以显著提升开发体验。本文博主将指导你如何在Vite+Vue3+TypeScript项目中配置前置路由守卫(NavigationGuards)。前置条件在开始配置项目前置路由守卫前,博主希望你能够先达成以下前置条件:1.完成Vue3前端项目搭建:Vite创建Vue3+TS项目2.引入</div> </li> <li><a href="/article/1883301698601021440.htm" title="JHipster入门 - 生成单体架构的应用" target="_blank">JHipster入门 - 生成单体架构的应用</a> <span class="text-muted">yorkwu1977</span> <a class="tag" taget="_blank" href="/search/%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B/1.htm">软件工程</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a> <div>JHipster入门-生成单体架构的应用目标准备工作生成基础功能输入指令开始问答环节问答环节结束,开始自动生成基础功能代码生成业务功能输入指令开始问答环节问答环节结束,开始自动生成业务功能代码调试启动启动后端服务启动前端服务访问前端页面打包启动构建启动访问前端页面关于数据库交给JHipster自己启动目标30分钟内生成一个开箱即用的单体架构应用。生成SpringBoot后端代码和Vue前端代码。基</div> </li> <li><a href="/article/1883280007913074688.htm" title="【Blazor】使用C#替代Java编写代码的前端开发框架" target="_blank">【Blazor】使用C#替代Java编写代码的前端开发框架</a> <span class="text-muted">雕技小虫</span> <a class="tag" taget="_blank" href="/search/%E7%B3%BB%E7%BB%9F%E5%BC%80%E5%8F%91/1.htm">系统开发</a><a class="tag" taget="_blank" href="/search/Windows/1.htm">Windows</a><a class="tag" taget="_blank" href="/search/Server/1.htm">Server</a><a class="tag" taget="_blank" href="/search/Blazor/1.htm">Blazor</a><a class="tag" taget="_blank" href="/search/.NET/1.htm">.NET</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91%E6%A1%86%E6%9E%B6/1.htm">前端开发框架</a><a class="tag" taget="_blank" href="/search/webassembly/1.htm">webassembly</a> <div>Blazor是微软于2019年下半年开始陆续全新推出的前端开发框架。优势无需插件,基于Web标准可与JavaScript交互利用.NETCore优势Blazor有两个版本:Server||WebAssemblyBlazorServer可以理解为在服务器上运行的Blazor,客户端与服务器间通过SignalR实进通信,2019年09月正式发布。BlazorWebAssembly2020年05月正式发</div> </li> <li><a href="/article/1883243422161104896.htm" title="fuadmin" target="_blank">fuadmin</a> <span class="text-muted">jcsx</span> <a class="tag" taget="_blank" href="/search/%E5%BC%80%E6%BA%90%E5%AD%A6%E4%B9%A0/1.htm">开源学习</a><a class="tag" taget="_blank" href="/search/django/1.htm">django</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a> <div>fu-admin-web采用VUE3,TS开发。fu-admin-backend采用Python,Django和Django-Ninija开发。数据库支持MySql,SqlServer,Sqlite。‍‍前端采用VbenAdmin、Vue3、AntDesignVue。后端采用Python语言Django框架以及强大的DjangoNinja。支持加载动态权限菜单,多方式轻松权限控制。Vue2项目移步</div> </li> <li><a href="/article/1883242286221946880.htm" title="docker容器基础入门" target="_blank">docker容器基础入门</a> <span class="text-muted">霉逝</span> <a class="tag" taget="_blank" href="/search/docker/1.htm">docker</a><a class="tag" taget="_blank" href="/search/%E5%AE%B9%E5%99%A8/1.htm">容器</a><a class="tag" taget="_blank" href="/search/%E8%BF%90%E7%BB%B4/1.htm">运维</a> <div>docker容器技术基础入门文章目录docker容器技术基础入门@[toc]1.docker基本概念2.Docker的引擎的组成以及功能3.docker的架构4.docker安装、配置加速器以及常用指令4.1安装docker软件包4.2开启docker并查看状态4.3配置阿里云镜像加速器4.4docker常用命令1.docker基本概念docker是容器技术的一个前端工具,容器是内核的一项技术,d</div> </li> <li><a href="/article/1883217441463529472.htm" title="前端构建工具" target="_blank">前端构建工具</a> <span class="text-muted">光影少年</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E8%BD%AF%E4%BB%B6%E6%9E%84%E5%BB%BA/1.htm">软件构建</a> <div>前端构建工具是开发现代Web应用时不可或缺的工具,用于优化代码、提升开发效率、以及实现高效的构建和部署。以下是常见的前端构建工具及其作用:1.模块打包工具Webpack特点:功能强大,插件与配置灵活。作用:将模块(JS、CSS、图片等)打包成浏览器可运行的文件。适用场景:中大型项目,需高度自定义。Vite特点:轻量、快速构建,基于ESModules。作用:适合现代框架如Vue、React,热更新速</div> </li> <li><a href="/article/1883209494624792576.htm" title="Vue.js组件开发研究" target="_blank">Vue.js组件开发研究</a> <span class="text-muted">清北互联木材</span> <a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a> <div>摘要随着前端技术的快速发展,Vue.js以其轻量级、高性能和组件化开发的优势,在前端开发领域占据了重要地位。本研究深入探讨了Vue.js组件开发的理论基础、开发方法以及实际应用。通过系统梳理Vue.js框架的核心特性、组件化思想及Vue.js组件的基本概念,本研究为Vue.js组件开发提供了全面的理论支撑。进一步地,本研究详细介绍了Vue.js组件的设计原则、组成要素及组件之间的关系,并阐述了组件</div> </li> <li><a href="/article/1883206217493442560.htm" title="什么是vue.js组件开发,我们需要做哪些准备工作?" target="_blank">什么是vue.js组件开发,我们需要做哪些准备工作?</a> <span class="text-muted">大懒猫软件</span> <a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a> <div>Vue.js是一个非常流行的前端框架,用于构建用户界面。组件开发是Vue.js的核心概念之一,通过将界面拆分为独立的组件,可以提高代码的可维护性和复用性。以下是一个详细的Vue.js组件开发指南,包括基础概念、开发流程和代码示例。一、Vue.js组件开发基础1.组件的基本结构Vue.js组件是一个独立的、可复用的UI元素。每个组件都有自己的模板、逻辑和样式。组件的基本结构如下:vue复制{{tit</div> </li> <li><a href="/article/1883203064614154240.htm" title="1.7K star!AI Cover:开源的红包封面[特殊字符]生成器,赶快收藏!" target="_blank">1.7K star!AI Cover:开源的红包封面[特殊字符]生成器,赶快收藏!</a> <span class="text-muted">前端后花园</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E7%83%AD%E9%97%A8%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE/1.htm">前端热门开源项目</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/github/1.htm">github</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E4%BB%A3%E7%A0%81%E7%89%87%E6%AE%B5/1.htm">代码片段</a> <div>欢迎来到前端后花园!我们专注分享前端开源项目,目标是探索分享精选100个高质量的开源项目。这是系列的第3篇文章,分享一个AI红包封面生成开源项目。大家好,我是小前!想要制作一款红包封面?却不懂PS,没关系,小前今天分享的开源项目-AI红包封面生成,输入提示词(eg.蛇年快乐)即可生成符合设计规范的红包封面,快来看看吧!简介AICover是一款开源的红包封面生成器,输入要生成的红包描述,即可快速生成</div> </li> <li><a href="/article/1883197394531708928.htm" title="python实战项目34:基于flask的天气数据可视化系统1.0" target="_blank">python实战项目34:基于flask的天气数据可视化系统1.0</a> <span class="text-muted">wp_tao</span> <a class="tag" taget="_blank" href="/search/Python%E5%89%AF%E4%B8%9A%E6%8E%A5%E5%8D%95%E5%AE%9E%E6%88%98%E9%A1%B9%E7%9B%AE/1.htm">Python副业接单实战项目</a><a class="tag" taget="_blank" href="/search/flask/1.htm">flask</a><a class="tag" taget="_blank" href="/search/%E4%BF%A1%E6%81%AF%E5%8F%AF%E8%A7%86%E5%8C%96/1.htm">信息可视化</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>基于flask的天气数据可视化系统1.0一、效果展示二、flask简介三、图表绘制四、前端页面编写五、完整代码一、效果展示该flask项目相对简单入门,使用了flask框架、bootstrap前端技术,数据使用的是上一篇scrapy爬取城市天气数据中爬取到的数据。二、flask简介Flask是一个基于Python的Web开发框架,它以灵活、微框架著称,基于werkzeug的轻量级web框架,可提高</div> </li> <li><a href="/article/1883182244529500160.htm" title="GB/T28181 全栈开发日记[6]:React 快速接入 jessibuca.js 播放器" target="_blank">GB/T28181 全栈开发日记[6]:React 快速接入 jessibuca.js 播放器</a> <span class="text-muted">gospace</span> <a class="tag" taget="_blank" href="/search/%E4%BB%8E/1.htm">从</a><a class="tag" taget="_blank" href="/search/0/1.htm">0</a><a class="tag" taget="_blank" href="/search/%E5%88%B0%E5%AE%9E%E7%8E%B0/1.htm">到实现</a><a class="tag" taget="_blank" href="/search/GB%2FT/1.htm">GB/T</a><a class="tag" taget="_blank" href="/search/28181/1.htm">28181</a><a class="tag" taget="_blank" href="/search/%E5%8D%8F%E8%AE%AE%E7%9A%84%E5%AE%8C%E6%95%B4%E5%AE%9E%E8%B7%B5/1.htm">协议的完整实践</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/%E9%9F%B3%E8%A7%86%E9%A2%91/1.htm">音视频</a> <div>GB/T28181全栈开发日记[6]:React快速接入jessibuca.js播放器服务端源代码github.com/gowvp/gb28181前端源代码github.com/gowvp/gb28181_web介绍GoWVP(GolangWebVideoPlatfrom)是一个Go语言实现的,基于GB28181-2022标准实现的网络视频平台,负责实现核心信令与设备管理后台部分,支持海康、大华、</div> </li> <li><a href="/article/1883174041729167360.htm" title="DB项目前端分支思考" target="_blank">DB项目前端分支思考</a> <span class="text-muted"></span> <a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a> <div>背景一般的项目基本是一个主分支持续的迭代开发。比如有一个master分支,这个分支是可以随时发布版本的。还有一个开发分支,比如develop,是从master检出的。当迭代开始的时候,从develop分支检出feature-xxx分支来做开发需求功能。当联调完成后,提MR合并到develop分支。以此类推,这里就不展开讲了。一般的项目往往只有一个环境,比如开发-测试-生产。但DB项目会存在各种各样</div> </li> <li><a href="/article/1883172537957937152.htm" title="Nginx部署前端Vue项目的深度解析" target="_blank">Nginx部署前端Vue项目的深度解析</a> <span class="text-muted">egekm_sefg</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/nginx/1.htm">nginx</a> <div>目录一、准备工作1.1开发环境1.2服务器环境1.3Nginx安装二、构建Vue项目三、上传静态文件到服务器四、配置Nginx五、测试并重新加载Nginx六、访问Vue应用七、高级配置7.1启用HTTPS7.2启用Gzip压缩7.3缓存控制八、常见问题与解决方案8.1404错误8.2权限问题8.3跨域问题九、总结在现代Web开发中,Vue.js因其组件化、响应式数据绑定和易于上手的特点,成为了前端</div> </li> <li><a href="/article/1883150221274312704.htm" title="70.在 Vue 3 中使用 OpenLayers 拖拽实现放大区域的效果(DragZoom)" target="_blank">70.在 Vue 3 中使用 OpenLayers 拖拽实现放大区域的效果(DragZoom)</a> <span class="text-muted">吉檀迦俐</span> <a class="tag" taget="_blank" href="/search/OpenLayers/1.htm">OpenLayers</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/openlayers/1.htm">openlayers</a> <div>引言在现代Web开发中,地图功能已经成为许多应用的重要组成部分。OpenLayers是一个功能强大的开源地图库,支持多种地图源和交互操作。Vue3是一个流行的前端框架,以其响应式数据和组件化开发著称。本文将介绍如何在Vue3中集成OpenLayers,并实现拖拽放大区域的效果(DragZoom)。实现效果按住Shift键,使用鼠标左键圈选区域,地图会自动放大到选中的区域。支持地图的拖拽、缩放等基本</div> </li> <li><a href="/article/1883129801779245056.htm" title="免费开源的后端API服务-supabase安装和使用-简直是前端学习者福音" target="_blank">免费开源的后端API服务-supabase安装和使用-简直是前端学习者福音</a> <span class="text-muted">前端三评</span> <a class="tag" taget="_blank" href="/search/strapi/1.htm">strapi</a><a class="tag" taget="_blank" href="/search/Ajax/1.htm">Ajax</a><a class="tag" taget="_blank" href="/search/%E5%B7%A5%E5%85%B7/1.htm">工具</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E6%BA%90/1.htm">开源</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/supabase/1.htm">supabase</a> <div>文章目录它是什么安装和部署关于安装关于部署1、注册用户2、创建组织3、创建项目创建数据库表(填充内容)填充数据库表使用postman联调API它是什么一个开源免费的后端框架,firebase的替代品。可以简单理解类似于headlesscms,但是不仅仅只提供内容,它还集成了服务订阅、即时API,用户身份认证(包括第三方身份认证,比如使用github、Google等账号实现快速登录和注册)、边缘函数</div> </li> <li><a href="/article/1883112025350008832.htm" title="前端新手如何用vite构建小程序中使用的模块(以AES加密模块crypto-js为例)" target="_blank">前端新手如何用vite构建小程序中使用的模块(以AES加密模块crypto-js为例)</a> <span class="text-muted">warmbook</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">小程序</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a> <div>如果你只是想简单地把在vite项目中使用的模块引入到小程序中,不妨试试库模式。以crypto-js为例,你需要写两个JS文件:一个是构建脚本,类似于vite.config.js;//build.cjsconst{build}=require('vite'),path=require('path');build({publicDir:false,configFile:false,runtimeCom</div> </li> <li><a href="/article/1883111898992406528.htm" title="【原生JS】如何优雅地读、改location.search(queryString或GET参数)" target="_blank">【原生JS】如何优雅地读、改location.search(queryString或GET参数)</a> <span class="text-muted">warmbook</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a> <div>应用场景location.search完全由JS脚本管理,并且需要不刷新页面地修改其内容。例如在Oauth2授权中,如果是前端取参提交给后端API向平台方请求accessToken,需要及时删除GET参数中的code,以防用户刷新浏览器导致用失效的code处理登录。实现思路将queryString转为对象并用ES6的Proxy代理,在set、delete钩子中调用history.replaceSt</div> </li> <li><a href="/article/1883085285055590400.htm" title="基于 Node.js 的天气查询系统实现(附源码)" target="_blank">基于 Node.js 的天气查询系统实现(附源码)</a> <span class="text-muted">Kasper0121</span> <a class="tag" taget="_blank" href="/search/node.js/1.htm">node.js</a> <div>项目概述这是一个基于Node.js的全栈应用,前端使用原生JavaScript和CSS,后端使用Express框架,通过调用第三方天气API实现天气数据的获取和展示。主要功能默认显示多个主要城市的天气信息支持城市天气搜索响应式布局设计深色主题界面优雅的加载动画技术栈后端:Node.js+Express前端:HTML5+CSS3+JavaScriptHTTP客户端:AxiosAPI:天气API(v1</div> </li> <li><a href="/article/1883076966500855808.htm" title="前端 | 浏览器安全:XSS攻击、CSRF攻击、中间人攻击" target="_blank">前端 | 浏览器安全:XSS攻击、CSRF攻击、中间人攻击</a> <span class="text-muted">酒酿泡芙1217</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E5%AE%89%E5%85%A8/1.htm">安全</a><a class="tag" taget="_blank" href="/search/xss/1.htm">xss</a><a class="tag" taget="_blank" href="/search/csrf/1.htm">csrf</a> <div>1.XSS攻击1.1什么是XSS攻击XSS攻击指的是跨站脚本攻击,是一种代码注入攻击。攻击者通过在网站注入恶意脚本,使之在用户的浏览器上运行,从而盗用用户的信息如cookie等本质是因为网站没有对恶意代码进行过滤,与正常的代码混合在一起了,浏览器没有办法分辨那些脚本是可信的,从而导致了恶意代码的执行攻击者通过这种攻击方式可以进行一下操作:获取页面的数据,如DOM、cookie、localStora</div> </li> <li><a href="/article/1883050103674040320.htm" title="HTML&CSS :如此优雅丝滑的导航栏,你不看看吗?" target="_blank">HTML&CSS :如此优雅丝滑的导航栏,你不看看吗?</a> <span class="text-muted">前端Hardy</span> <a class="tag" taget="_blank" href="/search/CSS/1.htm">CSS</a><a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a> <div>这段代码创建了一个动态的导航栏,通过CSS技术实现了按钮的激活和悬停效果,以及动态背景效果,为页面添加了视觉吸引力和用户交互体验。大家复制代码时,可能会因格式转换出现错乱,导致样式失效。建议先少量复制代码进行测试,若未能解决问题,私信我,我会发送完整的压缩包给你演示效果HTML&CSS公众号关注:前端Hardybody{margin:0;padding:0;background-color:#07</div> </li> <li><a href="/article/1883007741149114368.htm" title="mybatisplus获取返回对象(自增ID)" target="_blank">mybatisplus获取返回对象(自增ID)</a> <span class="text-muted">笑发财了1</span> <a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a><a class="tag" taget="_blank" href="/search/jar/1.htm">jar</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/maven/1.htm">maven</a><a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a><a class="tag" taget="_blank" href="/search/%E4%B8%AA%E4%BA%BA%E5%BC%80%E5%8F%91/1.htm">个人开发</a> <div>需求有时候我们在数据库里设置了属性自增,在添加对象后,前端需要我们返回这个属性(对象)。做法1.在该实体类的自增主键上加上注解@TableId(value="journey_location_id"),后面的type是默认值可以不写。value为数据表中的字段名@TableId(value="journey_location_id",type=IdType.AUTO)privateintjourn</div> </li> <li><a href="/article/1882995514832646144.htm" title="Vue组件的概念与复用" target="_blank">Vue组件的概念与复用</a> <span class="text-muted">2401_85969651</span> <a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/visual/1.htm">visual</a><a class="tag" taget="_blank" href="/search/studio/1.htm">studio</a><a class="tag" taget="_blank" href="/search/code/1.htm">code</a> <div>目录一、引言二、为什么使用组件二、什么是Vue组件三、组件的复用优势四、组件复用的实现方式五、组件通信六、总结一、引言在Vue.js的世界里,组件是构建用户界面的基石。它们让我们能够以一种高效、可维护的方式开发复杂的前端应用。无论是初涉Vue的新手,还是有一定经验的开发者,深入理解组件的概念与复用机制,都能极大提升开发效率与代码质量。二、为什么使用组件随着前端应用日益复杂,页面功能愈发繁多,传统的</div> </li> <li><a href="/article/1882995513733738496.htm" title="Vue 组件的概念与复用" target="_blank">Vue 组件的概念与复用</a> <span class="text-muted">2401_85969651</span> <a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/visual/1.htm">visual</a><a class="tag" taget="_blank" href="/search/studio/1.htm">studio</a><a class="tag" taget="_blank" href="/search/code/1.htm">code</a> <div>目录一、引言二、什么是Vue组件三、组件的复用优势四、组件复用的实现方式五、组件通信六、总结一、引言在Vue.js的奇妙天地里,组件宛如熠熠生辉的基石,稳稳撑起用户界面构建的大厦。无论你是刚踏入Vue领域的新手,还是久经沙场的开发者,吃透组件的概念与复用窍门,都如同掌握了一把开启高效开发、优质代码大门的金钥匙,能让你的前端开发之旅畅行无阻。二、什么是Vue组件本质上,Vue组件就是一个被赋予独特魅</div> </li> <li><a href="/article/90.htm" title="java观察者模式" target="_blank">java观察者模式</a> <span class="text-muted">3213213333332132</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a><a class="tag" taget="_blank" href="/search/%E6%B8%B8%E6%88%8F/1.htm">游戏</a><a class="tag" taget="_blank" href="/search/%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F/1.htm">观察者模式</a> <div>观察者模式——顾名思义,就是一个对象观察另一个对象,当被观察的对象发生变化时,观察者也会跟着变化。 在日常中,我们配java环境变量时,设置一个JAVAHOME变量,这就是被观察者,使用了JAVAHOME变量的对象都是观察者,一旦JAVAHOME的路径改动,其他的也会跟着改动。 这样的例子很多,我想用小时候玩的老鹰捉小鸡游戏来简单的描绘观察者模式。 老鹰会变成观察者,母鸡和小鸡是</div> </li> <li><a href="/article/217.htm" title="TFS RESTful API 模拟上传测试" target="_blank">TFS RESTful API 模拟上传测试</a> <span class="text-muted">ronin47</span> <div>       TFS RESTful API 模拟上传测试。    细节参看这里:https://github.com/alibaba/nginx-tfs/blob/master/TFS_RESTful_API.markdown 模拟POST上传一个图片: curl --data-binary @/opt/tfs.png http</div> </li> <li><a href="/article/344.htm" title="PHP常用设计模式单例, 工厂, 观察者, 责任链, 装饰, 策略,适配,桥接模式" target="_blank">PHP常用设计模式单例, 工厂, 观察者, 责任链, 装饰, 策略,适配,桥接模式</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a><a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a> <div>// 多态, 在JAVA中是这样用的, 其实在PHP当中可以自然消除, 因为参数是动态的, 你传什么过来都可以, 不限制类型, 直接调用类的方法 abstract class Tiger { public abstract function climb(); } class XTiger extends Tiger { public function climb()</div> </li> <li><a href="/article/471.htm" title="hibernate" target="_blank">hibernate</a> <span class="text-muted">171815164</span> <a class="tag" taget="_blank" href="/search/Hibernate/1.htm">Hibernate</a> <div>main,save Configuration conf =new Configuration().configure(); SessionFactory sf=conf.buildSessionFactory(); Session sess=sf.openSession(); Transaction tx=sess.beginTransaction(); News a=new </div> </li> <li><a href="/article/598.htm" title="Ant实例分析" target="_blank">Ant实例分析</a> <span class="text-muted">g21121</span> <a class="tag" taget="_blank" href="/search/ant/1.htm">ant</a> <div>        下面是一个Ant构建文件的实例,通过这个实例我们可以很清楚的理顺构建一个项目的顺序及依赖关系,从而编写出更加合理的构建文件。           下面是build.xml的代码: <?xml version="1</div> </li> <li><a href="/article/725.htm" title="[简单]工作记录_接口返回405原因" target="_blank">[简单]工作记录_接口返回405原因</a> <span class="text-muted">53873039oycg</span> <a class="tag" taget="_blank" href="/search/%E5%B7%A5%E4%BD%9C/1.htm">工作</a> <div>         最近调接口时候一直报错,错误信息是:       responseCode:405 responseMsg:Method Not Allowed        接口请求方式Post. </div> </li> <li><a href="/article/852.htm" title="关于java.lang.ClassNotFoundException 和 java.lang.NoClassDefFoundError 的区别" target="_blank">关于java.lang.ClassNotFoundException 和 java.lang.NoClassDefFoundError 的区别</a> <span class="text-muted">程序员是怎么炼成的</span> <div>   真正完成类的加载工作是通过调用 defineClass来实现的;  而启动类的加载过程是通过调用 loadClass来实现的;  就是类加载器分为加载和定义   protected Class<?> findClass(String name) throws ClassNotFoundExcept</div> </li> <li><a href="/article/979.htm" title="JDBC学习笔记-JDBC详细的操作流程" target="_blank">JDBC学习笔记-JDBC详细的操作流程</a> <span class="text-muted">aijuans</span> <a class="tag" taget="_blank" href="/search/jdbc/1.htm">jdbc</a> <div>所有的JDBC应用程序都具有下面的基本流程:  1、加载数据库驱动并建立到数据库的连接。  2、执行SQL语句。  3、处理结果。  4、从数据库断开连接释放资源。 下面我们就来仔细看一看每一个步骤: 其实按照上面所说每个阶段都可得单独拿出来写成一个独立的类方法文件。共别的应用来调用。 1、加载数据库驱动并建立到数据库的连接:   Html代码  St</div> </li> <li><a href="/article/1106.htm" title="rome创建rss" target="_blank">rome创建rss</a> <span class="text-muted">antonyup_2006</span> <a class="tag" taget="_blank" href="/search/tomcat/1.htm">tomcat</a><a class="tag" taget="_blank" href="/search/cms/1.htm">cms</a><a class="tag" taget="_blank" href="/search/xml/1.htm">xml</a><a class="tag" taget="_blank" href="/search/struts/1.htm">struts</a><a class="tag" taget="_blank" href="/search/Opera/1.htm">Opera</a> <div>引用 1.RSS标准 RSS标准比较混乱,主要有以下3个系列 RSS 0.9x / 2.0 : RSS技术诞生于1999年的网景公司(Netscape),其发布了一个0.9版本的规范。2001年,RSS技术标准的发展工作被Userland Software公司的戴夫 温那(Dave Winer)所接手。陆续发布了0.9x的系列版本。当W3C小组发布RSS 1.0后,Dave W</div> </li> <li><a href="/article/1233.htm" title="html表格和表单基础" target="_blank">html表格和表单基础</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/%E8%A1%A8%E6%A0%BC/1.htm">表格</a><a class="tag" taget="_blank" href="/search/%E8%A1%A8%E5%8D%95/1.htm">表单</a><a class="tag" taget="_blank" href="/search/meta/1.htm">meta</a><a class="tag" taget="_blank" href="/search/%E9%94%9A%E7%82%B9/1.htm">锚点</a> <div>第一次用html来写东西,感觉压力山大,每次看见别人发的都是比较牛逼的 再看看自己什么都还不会,   html是一种标记语言,其实很简单都是固定的格式   _----------------------------------------表格和表单 表格是html的重要组成部分,表格用在body里面的 主要用法如下; <table> &</div> </li> <li><a href="/article/1360.htm" title="ibatis如何传入完整的sql语句" target="_blank">ibatis如何传入完整的sql语句</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a><a class="tag" taget="_blank" href="/search/ibatis/1.htm">ibatis</a> <div>        ibatis如何传入完整的sql语句?进一步说,String str ="select * from test_table",我想把str传入ibatis中执行,是传递整条sql语句。         解决办法: <</div> </li> <li><a href="/article/1487.htm" title="精通Oracle10编程SQL(14)开发动态SQL" target="_blank">精通Oracle10编程SQL(14)开发动态SQL</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/plsql/1.htm">plsql</a> <div>/* *开发动态SQL */ --使用EXECUTE IMMEDIATE处理DDL操作 CREATE OR REPLACE PROCEDURE drop_table(table_name varchar2) is sql_statement varchar2(100); begin sql_statement:='DROP TABLE '||table_name; </div> </li> <li><a href="/article/1614.htm" title="【Linux命令】Linux工作中常用命令" target="_blank">【Linux命令】Linux工作中常用命令</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/linux%E5%91%BD%E4%BB%A4/1.htm">linux命令</a> <div>不断的总结工作中常用的Linux命令   1.查看端口被哪个进程占用   通过这个命令可以得到占用8085端口的进程号,然后通过ps -ef|grep 进程号得到进程的详细信息   netstat -anp | grep 8085   察看进程ID对应的进程占用的端口号   netstat -anp | grep 进程ID &</div> </li> <li><a href="/article/1741.htm" title="优秀网站和文档收集" target="_blank">优秀网站和文档收集</a> <span class="text-muted">白糖_</span> <a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%AB%99/1.htm">网站</a> <div>集成 Flex, Spring, Hibernate 构建应用程序   性能测试工具-JMeter   Hmtl5-IOCN网站   Oracle精简版教程网站   鸟哥的linux私房菜   Jetty中文文档   50个jquery必备代码片段   swfobject.js检测flash版本号工具</div> </li> <li><a href="/article/1868.htm" title="angular.extend" target="_blank">angular.extend</a> <span class="text-muted">boyitech</span> <a class="tag" taget="_blank" href="/search/AngularJS/1.htm">AngularJS</a><a class="tag" taget="_blank" href="/search/angular.extend/1.htm">angular.extend</a><a class="tag" taget="_blank" href="/search/AngularJS+API/1.htm">AngularJS API</a> <div>angular.extend 复制src对象中的属性去dst对象中. 支持多个src对象. 如果你不想改变一个对象,你可以把dst设为空对象{}: var object = angular.extend({}, object1, object2). 注意: angular.extend不支持递归复制. 使用方法: angular.extend(dst, src); 参数: </div> </li> <li><a href="/article/1995.htm" title="java-谷歌面试题-设计方便提取中数的数据结构" target="_blank">java-谷歌面试题-设计方便提取中数的数据结构</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>网上找了一下这道题的解答,但都是提供思路,没有提供具体实现。其中使用大小堆这个思路看似简单,但实现起来要考虑很多。 以下分别用排序数组和大小堆来实现。 使用大小堆: import java.util.Arrays; public class MedianInHeap { /** * 题目:设计方便提取中数的数据结构 * 设计一个数据结构,其中包含两个函数,1.插</div> </li> <li><a href="/article/2122.htm" title="ajaxFileUpload 针对 ie jquery 1.7+不能使用问题修复版本" target="_blank">ajaxFileUpload 针对 ie jquery 1.7+不能使用问题修复版本</a> <span class="text-muted">Chen.H</span> <a class="tag" taget="_blank" href="/search/ajaxFileUpload/1.htm">ajaxFileUpload</a><a class="tag" taget="_blank" href="/search/ie6/1.htm">ie6</a><a class="tag" taget="_blank" href="/search/ie7/1.htm">ie7</a><a class="tag" taget="_blank" href="/search/ie8/1.htm">ie8</a><a class="tag" taget="_blank" href="/search/ie9/1.htm">ie9</a> <div>jQuery.extend({ handleError: function( s, xhr, status, e ) { // If a local callback was specified, fire it if ( s.error ) { s.error.call( s.context || s, xhr, status, e ); } </div> </li> <li><a href="/article/2249.htm" title="[机器人制造原则]机器人的电池和存储器必须可以替换" target="_blank">[机器人制造原则]机器人的电池和存储器必须可以替换</a> <span class="text-muted">comsci</span> <a class="tag" taget="_blank" href="/search/%E5%88%B6%E9%80%A0/1.htm">制造</a> <div>        机器人的身体随时随地可能被外来力量所破坏,但是如果机器人的存储器和电池可以更换,那么这个机器人的思维和记忆力就可以保存下来,即使身体受到伤害,在把存储器取下来安装到一个新的身体上之后,原有的性格和能力都可以继续维持.....        另外,如果一</div> </li> <li><a href="/article/2376.htm" title="Oracle Multitable INSERT 的用法" target="_blank">Oracle Multitable INSERT 的用法</a> <span class="text-muted">daizj</span> <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a> <div>转载Oracle笔记-Multitable INSERT 的用法 http://blog.chinaunix.net/uid-8504518-id-3310531.html 一、Insert基础用法 语法:     Insert Into 表名 (字段1,字段2,字段3...)     Values (值1,</div> </li> <li><a href="/article/2503.htm" title="专访黑客历史学家George Dyson" target="_blank">专访黑客历史学家George Dyson</a> <span class="text-muted">datamachine</span> <a class="tag" taget="_blank" href="/search/on/1.htm">on</a> <div>20世纪最具威力的两项发明——核弹和计算机出自同一时代、同一群年青人。可是,与大名鼎鼎的曼哈顿计划(第二次世界大战中美国原子弹研究计划)相 比,计算机的起源显得默默无闻。出身计算机世家的历史学家George Dyson在其新书《图灵大教堂》(Turing’s Cathedral)中讲述了阿兰·图灵、约翰·冯·诺依曼等一帮子天才小子创造计算机及预见计算机未来</div> </li> <li><a href="/article/2630.htm" title="小学6年级英语单词背诵第一课" target="_blank">小学6年级英语单词背诵第一课</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/english/1.htm">english</a><a class="tag" taget="_blank" href="/search/word/1.htm">word</a> <div>always 总是 rice 水稻,米饭 before 在...之前 live 生活,居住   usual 通常的 early 早的 begin 开始 month 月份   year 年 last 最后的 east 东方的 high 高的   far 远的 window 窗户 world 世界 than 比...更   </div> </li> <li><a href="/article/2757.htm" title="在线IT教育和在线IT高端教育" target="_blank">在线IT教育和在线IT高端教育</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/%E6%95%99%E8%82%B2/1.htm">教育</a> <div>codecademy  http://www.codecademy.com codeschool  https://www.codeschool.com teamtreehouse  http://teamtreehouse.com lynda http://www.lynda.com/ Coursera https://www.coursera.</div> </li> <li><a href="/article/2884.htm" title="Struts2 xml校验框架所定义的校验文件" target="_blank">Struts2 xml校验框架所定义的校验文件</a> <span class="text-muted">蕃薯耀</span> <a class="tag" taget="_blank" href="/search/Struts2+xml%E6%A0%A1%E9%AA%8C/1.htm">Struts2 xml校验</a><a class="tag" taget="_blank" href="/search/Struts2+xml%E6%A0%A1%E9%AA%8C%E6%A1%86%E6%9E%B6/1.htm">Struts2 xml校验框架</a><a class="tag" taget="_blank" href="/search/Struts2%E6%A0%A1%E9%AA%8C/1.htm">Struts2校验</a> <div>  >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 蕃薯耀 2015年7月11日 15:54:59 星期六 http://fa</div> </li> <li><a href="/article/3011.htm" title="mac下安装rar和unrar命令" target="_blank">mac下安装rar和unrar命令</a> <span class="text-muted">hanqunfeng</span> <a class="tag" taget="_blank" href="/search/mac/1.htm">mac</a> <div>1.下载:http://www.rarlab.com/download.htm 选择 RAR 5.21 for Mac OS X 2.解压下载后的文件 tar -zxvf rarosx-5.2.1.tar 3.cd rar sudo install -c -o $USER unrar /bin #输入当前用户登录密码 sudo install -c -o $USER rar</div> </li> <li><a href="/article/3138.htm" title="三种将list转换为map的方法" target="_blank">三种将list转换为map的方法</a> <span class="text-muted">jackyrong</span> <a class="tag" taget="_blank" href="/search/list/1.htm">list</a> <div>  在本文中,介绍三种将list转换为map的方法: 1) 传统方法 假设有某个类如下    class Movie { private Integer rank; private String description; public Movie(Integer rank, String des</div> </li> <li><a href="/article/3265.htm" title="年轻程序员需要学习的5大经验" target="_blank">年轻程序员需要学习的5大经验</a> <span class="text-muted">lampcy</span> <a class="tag" taget="_blank" href="/search/%E5%B7%A5%E4%BD%9C/1.htm">工作</a><a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a><a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E5%91%98/1.htm">程序员</a> <div>在过去的7年半时间里,我带过的软件实习生超过一打,也看到过数以百计的学生和毕业生的档案。我发现很多事情他们都需要学习。或许你会说,我说的不就是某种特定的技术、算法、数学,或者其他特定形式的知识吗?没错,这的确是需要学习的,但却并不是最重要的事情。他们需要学习的最重要的东西是“自我规范”。这些规范就是:尽可能地写出最简洁的代码;如果代码后期会因为改动而变得凌乱不堪就得重构;尽量删除没用的代码,并添加</div> </li> <li><a href="/article/3392.htm" title="评“女孩遭野蛮引产致终身不育 60万赔偿款1分未得”医腐深入骨髓" target="_blank">评“女孩遭野蛮引产致终身不育 60万赔偿款1分未得”医腐深入骨髓</a> <span class="text-muted">nannan408</span> <div>先来看南方网的一则报道: 再正常不过的结婚、生子,对于29岁的郑畅来说,却是一个永远也无法实现的梦想。从2010年到2015年,从24岁到29岁,一张张新旧不一的诊断书记录了她病情的同时,也清晰地记下了她人生的悲哀。   粗暴手术让人发寒   2010年7月,在酒店做服务员的郑畅发现自己怀孕了,可男朋友却联系不上。在没有和家人商量的情况下,她决定堕胎。   12月5日,</div> </li> <li><a href="/article/3519.htm" title="使用jQuery为input输入框绑定回车键事件 VS 为a标签绑定click事件" target="_blank">使用jQuery为input输入框绑定回车键事件 VS 为a标签绑定click事件</a> <span class="text-muted">Everyday都不同</span> <a class="tag" taget="_blank" href="/search/jsp/1.htm">jsp</a><a class="tag" taget="_blank" href="/search/input/1.htm">input</a><a class="tag" taget="_blank" href="/search/%E5%9B%9E%E8%BD%A6%E9%94%AE%E7%BB%91%E5%AE%9A/1.htm">回车键绑定</a><a class="tag" taget="_blank" href="/search/click/1.htm">click</a><a class="tag" taget="_blank" href="/search/enter/1.htm">enter</a> <div>假设如题所示的事件为同一个,必须先把该js函数抽离出来,该函数定义了监听的处理:   function search() { //监听函数略...... }   为input框绑定回车事件,当用户在文本框中输入搜索关键字时,按回车键,即可触发search():   //回车绑定 $(".search").keydown(fun</div> </li> <li><a href="/article/3646.htm" title="EXT学习记录" target="_blank">EXT学习记录</a> <span class="text-muted">tntxia</span> <a class="tag" taget="_blank" href="/search/ext/1.htm">ext</a> <div>  1. 准备   (1) 官网:http://www.sencha.com/   里面有源代码和API文档下载。   EXT的域名已经从www.extjs.com改成了www.sencha.com ,但extjs这个域名会自动转到sencha上。   (2)帮助文档:   想要查看EXT的官方文档的话,可以去这里h</div> </li> <li><a href="/article/3773.htm" title="mybatis3的mapper文件报Referenced file contains errors" target="_blank">mybatis3的mapper文件报Referenced file contains errors</a> <span class="text-muted">xingguangsixian</span> <a class="tag" taget="_blank" href="/search/mybatis/1.htm">mybatis</a> <div>最近使用mybatis.3.1.0时无意中碰到一个问题: The errors below were detected when validating the file "mybatis-3-mapper.dtd" via the file "account-mapper.xml". In most cases these errors can be d</div> </li> </ul> </div> </div> </div> <div> <div class="container"> <div class="indexes"> <strong>按字母分类:</strong> <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a> </div> </div> </div> <footer id="footer" class="mb30 mt30"> <div class="container"> <div class="footBglm"> <a target="_blank" href="/">首页</a> - <a target="_blank" href="/custom/about.htm">关于我们</a> - <a target="_blank" href="/search/Java/1.htm">站内搜索</a> - <a target="_blank" href="/sitemap.txt">Sitemap</a> - <a target="_blank" href="/custom/delete.htm">侵权投诉</a> </div> <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved. <!-- <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>--> </div> </div> </footer> <!-- 代码高亮 --> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script> <link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/> <script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script> </body> </html>