前端开发小结 2019-09-30

最近需要开发前端页面,记录学习笔记

nodejs

nodejs 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。

npm

nodejs 的默认包装管理器,可以用于安装 nodejs 的模块。

使用方式

  • npm install ${package}
    本地安装。将安装包放到当前目录的 ./node_modules 下
    加参数 –save 可以同时将包依赖加入到 package.json 的 dependencies
    加参数 –save-dev 可以同时将包依赖加入到 package.json 的 devDependencies 节点下
  • npm install ${package} -g
    全局安装。将安装包放到 /usr/local 或者 nodejs 的安装目录。
  • package.json 文件
    放到工程目录,可以指定项目需要什么依赖,有哪些运行命令

yarn

也是 nodejs 的包管理工具

  • yarn init
    初始化一个项目
  • yarn install
    安装 package.json 中的依赖
  • yarn global add xxx
    全局安装
  • yarn add ${package}
    安装依赖,同时加到 package.json 的 dependencies 下
  • yarn add ${package} –dev
    安装依赖,同时加到 package.json 的 devDependencies 下
  • yarn list
    列出工程的所有依赖
  • yarn global list
    列出全局安装包
  • yarn config get registry
    查看安装源
  • yarn config set registry https://registry.npm.taobao.org
    切换为淘宝的安装源
  • yarn config set registry https://registry.yarnpkg.com
    切换为原来的安装源

nodejs 库

typescript

是 javascript 的一个超集,有类型检查

网上比较好的教程 TypeScript 入门教程

生成 typescript 应用的步骤有

  1. 生成 javascript 应用
  2. 添加 typescript 依赖
  3. 运行 node_modules.bin\tsc.cmd -init 生成 tsconfig.json

react

一个用于构建用户界面的 javascript 库,运行在 nodejs 环境

react-JSX

它允许 HTML 与 JavaScript 的混写

1
2
3
4
5
6
7
8
9
10
11
12
// 两个 div 是 html 标签,而标签内用花括号包起来的是 javascript
// JSX 允许直接在模板插入 JavaScript 变量,例如下面的 {name}
ReactDOM.render(
<div>
{
names.map(function (name) {
return <div>Hello, {name}!</div>
})
}
</div>,
document.getElementById('example')
);

react-组件

React 允许将代码封装成组件,然后像插入普通 HTML 标签一样使用组件。组件可以用类定义,必须有一个成员 render 用于渲染页面。

react-组件的 properties 和 state

  • props:表示组件的所有属性,属性在组件中是不可变的
  • state:react 将组件看成是一个状态机,有一个初始状态,然后用户互动导致状态变化,再渲染 UI。

react-组件生命周期

组件的生命周期分为 3 个状态

  • Mounting:已插入真实 DOM
  • Unmounting:已移出真实 DOM
  • Updating:正在被重新渲染

React 为每个状态都提供了两种处理函数,will 函数在进入状态之前调用,did 函数在进入状态之后调用,三种状态共计五种处理函数

  • componentWillMount()
  • componentDidMount()
  • componentWillUpdate(object nextProps, object nextState)
  • componentDidUpdate(object prevProps, object prevState)
  • componentWillUnmount()

create-react-app

用来生成 react 应用,并提供所有依赖和安装一个脚手架工具

全局安装后,可以用命令生成 react 工程

yarn create react-app ${appName}

react-app-rewired

用 create-react-app 生成的工程,在 package.json 会包含 react-scripts 依赖,而 react-scripts 会包含所有 react 的真正依赖以及配置
要想修改其中的配置(例如 webpack 的配置),需要用 eject 命令将所有依赖展开到 package.json 文件(不可逆)

react-app-rewired 的作用,就是在不 eject 的情况下,覆盖 create-react-app 的配置。

使用时,需要覆盖 package.json 中默认的 scripts 配置

1
2
3
4
5
6
7
8
9
10
{
...

"scripts": {
"start": "cross-env PORT=9080 react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
}

...

接着在工程根目录中创建一个 config-overrides.js 文件,然后在 config-overrides.js 中修改需要的配置。

react-dom

DOM 和 React renderers 的入口

大部分 react 应用由此开始

1
2

ReactDOM.render(${标记}), document.getElementById('root'));

cross-env

用于跨平台地设置及使用环境变量。Linux 和 Windows 中的环境变量语法不一样,用 cross-env 可以统一起来。

例如下面的代码定义了 PORT 变量

1
2
3
4
5
6
7
8
{
...

"scripts": {
"start": "cross-env PORT=9080 react-app-rewired start",

...
}

webpack

用于 js 压缩打包

antd

基于 react 的 UI 库

axios

ajax 库,用于 ajax 请求

less

一门 CSS 预处理语言,它扩展了 CSS 语言,增加了变量、Mixin、函数等特性,使 CSS 更易维护和扩展

redux

redux 是 javascript 状态容器,提供可预测化的状态管理,官网

使用 redux 会使应用变得复杂。以下场景适合使用 redux

  • 用户的使用方式复杂
  • 不同身份的用户有不同的使用方式(比如普通用户和管理员)
  • 多个用户之间可以协作
  • 与服务器大量交互,或者使用了 WebSocket
  • View 要从多个来源获取数据

redux 有两个基本的设计思想

  • web 应用是一个状态机,视图与状态是一一对应
  • 所有的状态,保存在一个对象里面

基本概念

  • store:就是保存数据的地方,可以把它看成一个容器,整个应用只能有一个 store。
  • state:是 store 对象包含所有数据。一个 state 对应一个 view,state 的变化,会导致 view 的变化。
    注:redux 里的 state 和 react 中的 state 是不同的概念
  • action:action 是 view 发出的通知,表示 state 要发生变化。action 有 type 属性的对象。
  • action creator:view 要发送多少种消息,就会有多少种 action。如果都手写,会很麻烦。可以定义一个函数来生成 action,这个函数就叫 action creator。
  • store.dispatch():调用后发出 action。
  • reducer:store 收到 action 以后,必须给出一个新的 state,这种 state 的计算过程就叫做 reducer。reducer 函数需要是一个纯函数。
    reducer 可以拆分成多个小的 reducer,由 combineReducers 组合起来。

redux 的一般工作流程如下图:
redux 工作流程图

store 提供一个 subscribe 函数用于注册监听函数,可以在监听函数中重新渲染页面。

react-redux

redux 官方提供的 react 绑定库,详细可看 Redux 中文文档

react-redux 将所有组件分成两大类:UI 组件(presentational component)和容器组件(container component)。

UI 组件的特性有

  • 只负责 UI 的呈现,不带有任何业务逻辑
  • 没有状态(即不使用this.state这个变量)
  • 所有数据都由参数(this.props)提供
  • 不使用任何 Redux 的 API

窗口组件的特性有

  • 负责管理数据和业务逻辑,不负责 UI 的呈现
  • 带有内部状态
  • 使用 Redux 的 API

如果一个组件既有 UI 又有业务逻辑,将它拆分成外面是一个容器组件,里面包了一个 UI 组件。

react-redux 规定,所有的 UI 组件都由用户提供,容器组件则是由 react-redux 自动生成。也就是说,用户负责视觉层,状态管理则是全部交给它

react-redux 提供 connect 方法,用于从 UI 组件生成容器组件。connect 的意思,就是将这两种组件连起来。使用 connect 生成的新组件,当属性发生变量时,就会重新渲染页面

例如:

1
2
3
4
5
6
7
8
9
10
const NewCompent = connect (
mapStateToProps,
mapDispatchToProps
)(MyCompent))

ReactDOM.render (
<Provider store={store}>
<NewCompent />
</Provider>,
document.getElementById('root'));

mapStateToProps 是一个函数,建立一个从(外部的)state 对象到(UI 组件的)props 对象的映射关系。mapStateToProps 执行后应该返回一个对象,里面的每一个键值对就是一个映射
mapStateToProps 会订阅 Store,每当 state 更新的时候,就会自动执行,重新计算 UI 组件的参数,从而触发 UI 组件的重新渲染。

mapDispatchToProps 建立 UI 组件的参数到 store.dispatch 方法的映射,定义了哪些用户的操作应该当作 Action,传给 Store
如果 mapDispatchToProps 是一个函数,会得到 dispatch 和 ownProps(容器组件的 props 对象)两个参数
如果 mapDispatchToProps 是一个对象,它的每个键名也是对应 UI 组件的同名参数,键值应该是一个函数,会被当作 Action creator ,返回的 Action 会由 Redux 自动发出。

Provider 包装 store 对象,使得所有地方都可以获取 store 对象而不需要将 store 对象作参数到处传递。

redux-saga

redux 有一个 middleware 的组件,它提供的是位于 action 被发起之后,到达 reducer 之前的扩展点。而 redux-saga 就是这样的一个扩展的 middleware,用于管理应用程序 Side Effect(副作用,例如异步获取数据,访问浏览器缓存等)。比较好的教程有 redux-saga 中文教程

加入 saga 后的工作流程图

sage 提供了一套原语用来管理异步操作。在 redux-saga 的世界里,所有的任务都通用 yield Effects 来完成。Effects 都是简单的 Javascript 对象,可以看作是redux-saga 的任务单元。常见的原语有:

Saga 辅助函数,用来在一些特定的 action 被发起到 Store 时派生任务

  • takeEvery,表示每次 Action 被发起时,启动任务
  • takeLatest,表示只为最新被的 Action 启动任务

redux-saga 框架提供了很多创建 effect 的函数,常见的有

  • take(pattern)
    take函数可以理解为监听未来的 action,它创建了一个命令对象,告诉 middleware 等待一个特定的 action, Generator 会暂停,直到一个与 pattern 匹配的action 被发起,才会继续执行下面的语句。所以 take 是一个阻塞的 effect。
  • put(action)
    put 函数是用来发送 action 的 effect,可以简单的把它理解成为 redux 框架中的 dispatch 函数,当 put 一个 action 后,reducer 中就会计算新的 state 并返回。put 是阻塞的 effect。
  • call(fn, …args)
    call 函数可以把它简单的理解为就是可以调用其他函数的函数,它命令 middleware 来调用 fn 函数, args 为函数的参数。注意:fn 函数可以是一个 Generator 函数,也可以是一个返回 Promise 的普通函数,call 函数也是阻塞 effect。
  • fork(fn, …args)
    fork 函数和 call 函数很像,都是用来调用其他函数的,但是fork函数是非阻塞函数。
  • select(selector, …args)
    select 函数是用来指示 middleware 调用提供的选择器获取 Store 上的 state 数据,可以简单的把它理解为 redux 框架中获取 store 上的 state 数据一样的功能:store.getState()
1
2
3
4
5
// 创建一个 Redux 中间件,将 Sagas 与 Redux Store 链接起来
const sagaMiddleware = createSagaMiddleware();

// 动态执行 sagas,rootSaga 是一个 Generator 函数
sagaMiddleware.run(rootSaga);

react-router-dom

react 路由组件,实现页面间的跳转。

其他

redux-saga 使用了 ES6 的 Generator 功能,让异步的流程更易于读取,写入和测试。相关的资料有 Generator 函数的含义与用法