耦合度爆炸(划掉)函数式编程思想的具现化——React 框架
安装
有
- CDN 引入
- 本地安装
- 脚手架构建
共三种方法
CDN 引入
在 html 模板中引入至少三个 script
标签,示例如下
1 | <!-- 加载 React。--> |
本地安装
运行以下命令
1 | npm install -g react react-dom |
即可安装必要的两个包
在使用时通过
1 | import React from 'react' |
即可引入
脚手架构建
推荐使用该方法,但记得换源,不然就等着小时为单位的 installing 吧
换源命令如下
1 | npm config set registry https://registry.npm.taobao.org |
可以通过以下命令检查是否换源成功
1 | npm config get registry |
返回值是现在的源的路径
然后运行以下命令
1 | npm install -g create-react-app |
然后移动到 react 项目目录下,运行
1 | create-react-app demo |
即可创建一个 demo 文件夹,内含全套 react 项目
或是
1 | create-react-app . |
即可在当前目录下初始化一个 react 项目
开始
安装完成后,通过命令
1 | npm run start |
即可启动 react app,不出意外的话会自动打开 localhost:3000 并显示 react 默认页面
自带的热更新效果有限,想查看最新效果,最好还是手动刷新一下
打开 src/index.js
就可以看到主入口代码
暂时不需要考虑太多,只需要知道
ReactDOM.render
函数负责渲染页面React.StrictMode
标签是一个占位符,不会渲染到页面上,实际渲染的部分只有该占位符内部的部分React.createElement
函数可以创建一个 react 元素原则上模板必须是一个整体,不能是两个或多个并列的元素,但是可以使用
React.Fragment
标签做到整体的效果但是写
React.Fragment
也太多字母了,所以 react 提供了缩写<>
,与上述等效其对应的闭合标签是
</>
ReactDOM.render
的格式如下
1 | ReactDOM.render(template, target) |
第一个参数填写要渲染的模板
第二个参数填写模板要挂载到页面上的哪个位置
React.createElement
的格式如下
1 | React.createElement(type, props, text) |
第一个参数表示创建的类型,如 'div'
第二个参数表示该标签持有的属性,如 {className: 'container'}
第三个参数表示该标签内部的文本
模板
与 vue 的构造选项不同,react 采用独特的 JSX 语法来书写模板
在 index.js
中,我们可以看到,ReactDOM.render
函数实际渲染的部分是 <App />
标签,该标签通过
1 | import App from './App'; |
来引入 App 模块
那么我们打开 src/App.js
,可以看到该 js 通过
1 | export default App; |
向外暴露了一个名为 App 的 function,该 function 返回一段形似 HTML 的语段,这个语段所采用的语法就是 JSX
JSX 语法要注意的地方有 3 个
总体上沿用 HTML 语法
需要使用 js 来表示的地方(如变量或函数),使用花括号
{}
来表示与 vue 不同,vue 是使用双花括号
1
{{}}
来表示
可以添加任意自定义参数,但要注意有的参数有细微变化
- 原参数名 class,现在变为 className
- 原参数名 onclick,现在变为 onClick,其余事件同理
- 一般有断句的部分,都要同 2 一样变成驼峰,用到的话请查一下文档
需要注意的是,js 中的 return 后如果留空,则实际等效于 return undefined
,所以要用一对圆括号来占这一行的位置,然后折行写 JSX
魔改
实现 +1
现在魔改一下 App 中的 JSX,来做一个简单的 +1 功能
显然,+1 需要一个变量来承载值,一个 button 来触发事件
容易得到以下 JSX
1 | import './App.css'; |
但是这时候发现,无论如何点击 button,n 都不会变化!
这是因为 react 和 vue 不同,不会自动监听数据变化并刷新视图
如果想要刷新视图,需要手动调用 render 函数
那么容易得到以下变体
1 | import { render } from 'react-dom'; |
现在点击页面上的 button,可以正常 +1 并重新渲染了,但是这也太丑了吧?!
代码优化
那么我们可以使用一个变量来保存我们的模板
容易得到以下变体
1 | import { render } from 'react-dom'; |
但是现在发现 +1 坏掉了!
为什么?因为 template 在声明的时候,就已经是一个静态的常量了,计算好了 n 的值,之后不会重新取得 n 的值
那延后 n 的取值行不行?容易想到用函数来装载模板,但是 JSX 支持吗?
答案是支持!render 函数的第一个参数可以是
一段 JSX 语段
一个返回 JSX 语段的函数,此时会自动执行函数取返回值
但是此时 render 第一个参数必须写成标签形式
那么箭头函数就可以满足我们的目标
1 | import { render } from 'react-dom'; |
这时发现——为什么控制台报错,页面不显示了!
答案是,我们向外暴露的是 App 函数,而 App 函数返回一个函数,在 index.js 中被调用时没有正常返回一段 JSX
于是我们把 JSX 移动到 App 中
1 | import { render } from 'react-dom'; |
成功了!注意,此时 App 一般是用作标签写法,所以最好是大写开头
现在我们得到了 +1 的功能和一段好看的代码
于是又带来了另一个问题——看起来似乎 render 的时候更新的是整个 template,真的吗?
部分重新渲染
显然 n 是变化的,但是 button 的逻辑似乎没有变化,这样不会过度渲染吗?
我们可以用开发者工具在页面上给 button 加一个 id,然后再点击一下试试,发现 button 还是带有 id!
那么我们就可以得到一个结论—— react 知道哪些要改,哪些不用改,在重新渲染的时候只会更新有变化的部分
可是 react 是怎么知道的呢?这就涉及虚拟 DOM 和 DOM diff 算法了
大致就是,react 将页面上的真实 DOM 解析到内存中,建立了一棵内存中的 DOM 树,然后每次重新渲染的时候都会先在内存中比较(其实 vue 也是这么做的)
此处不展开讲,有兴趣的话可以搜搜本站的文章,不过我可能还没写
条件与循环
条件
现在我想自动检测 n 是奇数还是偶数,怎么办呢
容易想到在 App 中加入条件判断
1 | let App = () => ( |
这样就可以了
什么,你说想要 vue 那种,也可以吧
1 | import { render } from 'react-dom'; |
此时 App 兼有了更复杂的功能,一般称为函数组件
循环
想展示一个数组,又该怎么办呢
假设有以下数组
1 | const array = [ |
可以得到以下 JSX
1 | import { render } from 'react-dom'; |
注意,此时我们要循环得到多个 li 标签,所以要先用 {}
来进行 js 循环
然后在 return 的 li 标签中,又是新的 JSX 语法作用域,可以继续使用 {}
来取值
显示结果如下
1 | · 第1位:name = ringoer, age = 22 |
展望
上文中提到了函数组件,但并未详细说明
实际上,react 组件一般使用类组件和函数组件,其中又以函数组件为最方便且常用的写法
敬请期待吧
感谢阅读