React技术要点总结

React技术要点总结


JSX:
组件:组件名称必须以大写字母为开头,html标签使用小写开头
部件
props:JSX属性作为单个对象传递给该组件

Ant design实践教程

第一章 基础知识

第二章 布局与路由

第三章 小试牛刀DVA-状态管理和model

使用model

一个简单的model示例:

app.model({

  namespace: 'todoList',

  state: [],

  effects: {
    *query({ _ }, { put, call }) {
      const rsp = yield call(queryTodoListFromServer);
      const todoList = rsp.data;
      yield put({ type: 'save', payload: todoList });
    },
  },

  reducers: {
    save(state, { payload: todoList }) {
      return [...state, todoList];
    },
  },

});

DVA 的 model 对象有几个基本的属性,需要大家了解。

  1. namespace:model 的命名空间,只能用字符串。一个大型应用可能包含多个 model,通过namespace区分。
  2. state:当前 model 状态的初始值,表示当前状态。
  3. reducers:用于处理同步操作,可以修改 state,由 action 触发。reducer 是一个纯函数,它接受当前的 state 及一个数据体(payload)作为入参,返回一个新的 state。
  4. effects:用于处理异步操作(例如:与服务端交互)和业务逻辑,也是由 action 触发。但是,它不可以修改 state,要通过触发 action 调用 reducer 实现对 state 的间接操作。
  5. action:是 reducers 及 effects 的触发器,一般是一个对象,形如{ type: ‘add’, payload: todo },通过 type 属性可以匹配到具体某个 reducer 或者 effect,payload 属性则是数据体,用于传送给 reducer 或 effect。
基本model 的使用-dispatch、action、reducer

dva 可以帮助我们把 state 上提到 所有 React 组件之上,过程是相似的:

  • 页面通过调用 dispatch 函数来驱动 dva model state 的改变;
  • 改变后的 dva model state通过 connect 方法注入页面。

首先,注意 dva model 的定义。一个基本的 dva model 最少具备两个成员:namespace 和 state。namespace 来作为一个 model 的唯一标识,state 中就是该 model 管理的数据。

其次,看页面文件的变化:我们删除了组件本身的 state,同时添加了 @connect(mapStateToProps)。connect 是连接 dva 和 React 两个平行世界的关键,一定要理解。

  • connect 让组件获取到两样东西:1. model 中的数据;2. 驱动 model 改变的方法。
  • connect 本质上只是一个 javascript 函数,通过 @ 装饰器语法使用,放置在组件定义的上方;
  • connect 既然是函数,就可以接受入参,第一个入参是最常用的,它需要是一个函数,我们习惯给它命名叫做 mapStateToProps,顾名思义就是把 dva model 中的 state 通过组件的 props 注入给组件。通过实现这个函数,我们就能实现把 dva model 的 state 注入给组件。
model中请求服务端effect

dva的精髓在于effect,类似于中间件middleware。

" Middleware is some code you can put between the framework receiving a request, and the framework generating a response. "

在上一章中 action 被 dispatch 之后就能够 直接 到达 reducer。为了保证 reducer 的纯粹性,但同时又能够处理副作用,就需要打破「直接」这个特性。effect 充当了这么一个中间层,当 action 被 dispatch 之后,会先到达 effect 处理副作用,然后该 effect 最终会促使新的 action 发送出去,这个新的 action 可能被其他的 effect 再捕获继续处理,也可能被 reducer 捕获并结束,无论怎样,最终处理逻辑的终点都将是 reducer。

模拟服务器端数据功能

第四章 复杂页面

antd 提供了一套非常强大的表单组件,大部分情况下只需要简单的几步配置便可以实现验证功能。首先,我们需要将页面与表单进行关联:

export default connect(mapStateToProps)(Form.create()(List));
其中,最主要的代码是:

Form.create()(List)

这段代码的作用是创建一个高阶组件,为页面组件 List 提供表单所需要的内容(this.props.form)。

图表

图表在中后台系统中是一个非常常见的可视化表现形式,也使得数据变得更为的直观。这一小节,我们将通过使用图表类库 G2 来制作一个图表。

备注:阿里提供了 BizCharts 对 G2 进行了封装,在实际开发中可以很方便的进行使用。本小节会从基本的 G2 应用开始,让你体验一下组件开发需要涉及到哪些细节。

此处我们看到了一个新的属性 ref,通过该属性我们可以获取经过 render 后的真实节点的引用。

第五章 进阶功能

自定义样式

CSS modules与Less语法校核
更换antd主题
更改全局样式

上传与下载
  • 上传
    使用fetch进行上传
    使用antd的upload组件进行上传
  • 下载
    使用a标签实现文件下载
    使用fetch实现文件下载
生命周期

  • 装载期间
    组件被实例化并挂载在到DOM树这一过程称为装载,在装载期调用的生命周期函数依次为

constructor()
getDerivedStateFromProps()
render()
componentDidMount()

  • 更新期间
    当组件的状态或属性变化时会触发更新,更新过程中会依次调用以下方法:

getDerivedStateFromProps() 上文已描述,不赘述
componentWillUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()

  • 卸载期间
    卸载期间是指组件被从DOM树中移除时,调用的相关方法为:

componentWillUnmount()

  • 错误捕获
    React16中新增了一个生命周期函数:

componentDidCatch()

  • 总结
    总结一下,以上讲的这些生命周期都有自己存在的意义,但在React使用过程中我们最常用到的生命周期函数是如下几个:

constructor: 初始化状态,进行函数绑定
componentDidMount: 进行DOM操作,进行异步调用初始化页面
componentWillReceiveProps: 根据props更新状态
componentWillUnmount: 清理组件定时器,网络请求或者相关订阅等
参考链接

ES6语法

ES6 是下一代 JavaScript 语法标准,比起 ES5 有很大的变化。标准委员会每年发布一次当年度的新标准,目前最新的标准是《ES2018 标准》,因此 ES6 是一个动态的标准,每年都会发生一些变化。

React 大量使用 ES6 语法,本文介绍其中一些最重要的语法点。完整的 ES6 介绍请参考 http://es6.ruanyifeng.com/

let 和 const

letconst命令用于声明变量。

let声明的变量是可变的,const声明的变量是不可变的。

let foo = 1;
foo = 2;

const bar = 1;
bar = 2; // 报错

上面代码中,let声明的变量foo是可以重新赋值,但是如果对bar声明的变量重新赋值,就会报错。

注意,如果const声明的变量指向一个对象,那么该对象的属性是可变的。

const foo = {
  bar: 1
};

foo.bar = 2;

上面代码中,变量foo本身是不可变的,即foo不能指向另一个对象。但是,对象内部的属性是可变的,这是因为这时foo保存的是一个指针,这个指针本身不可变,但它指向的对象本身是可变的。

解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。

let [a, b, c] = [1, 2, 3];

上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。

解构赋值不仅可以用于数组,还可以用于对象。

let { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"

解构赋值时,还可以设置默认值。

let [x, y = 'b'] = ['a']; // x='a', y='b'

上面代码中,变量y解构赋值时没有取到值,所以默认值就生效了。

对象的简洁表示法

ES6 允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。

const foo = 'bar';
const baz = { foo };
baz // {foo: "bar"}

除了属性简写,方法也可以简写。

const o = {
  method() {
    return "Hello!";
  }
};

// 等同于

const o = {
  method: function() {
    return "Hello!";
  }
};

箭头函数

ES6 允许使用“箭头”(=>)定义函数。

var f = v => v;

// 等同于
var f = function (v) {
  return v;
};

如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。

var f = () => 5;
// 等同于
var f = function () { return 5 };

var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
  return num1 + num2;
};

如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。

var sum = (num1, num2) => { return num1 + num2; }

rest 参数

ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。

function add(...values) {
  let sum = 0;

  for (var val of values) {
    sum += val;
  }

  return sum;
}

add(2, 5, 3) // 10

上面代码的add函数是一个求和函数,利用 rest 参数,可以向该函数传入任意数目的参数。

扩展运算符

扩展运算符(spread)是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。

console.log(...[1, 2, 3])
// 1 2 3

console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5

[...document.querySelectorAll('div')]
// [<div>, <div>, <div>]

对象也可以使用扩展运算符。

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }

class

ES6 允许新建“类”(class)。

class SkinnedMesh extends THREE.Mesh {
  constructor(geometry, materials) {
    super(geometry, materials);

    this.idMatrix = SkinnedMesh.defaultMatrix();
    this.bones = [];
    this.boneMatrices = [];
    //...
  }
  update(camera) {
    //...
    super.update();
  }
  get boneCount() {
    return this.bones.length;
  }
  set matrixType(matrixType) {
    this.idMatrix = SkinnedMesh[matrixType]();
  }
  static defaultMatrix() {
    return new THREE.Matrix4();
  }
}

上面是一个类的定义。

  • constructor():构造函数,新建实例的时候,自动调用这个方法。
  • extends:第一行的extends关键字表示继承某个父类。
  • super:子类方法里面的super指代父类。
  • get():get是取值器,读取该方法定义的属性时,会自动执行指定的代码。
  • set():set是赋值器,赋值该方法定义的属性时,会自动执行指定的代码。
  • static:方法前面加上static关键字,表示该方法是静态方法,定义在类上面,而不是定义在实例对象上面,以上面为例,就是SkinnedMesh.defaultMatrix()这样调用。

定义了类以后,就可以新建实例了。

const instance = new SkinnedMesh();

Promise 对象

Promise 是 ES6 引入的封装异步操作的统一接口。它返回一个对象,包含了异步操作的信息。

Promise 本身是一个构造函数,提供了resolvereject两个方法。一旦异步操作成功结束,就调用resolve方法,将 Promise 实例对象的状态改为resolved,一旦异步操作失败,就调用reject方法,将 Promise 实例的状态改成rejected

function timeout(duration = 0) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, duration);
  })
}

上面代码中,timeout函数返回一个 Promise 实例,在指定时间以后,将状态改为resolved

var p = timeout(1000).then(() => {
  return timeout(2000);
}).then(() => {
  throw new Error("hmm");
}).catch(err => {
  return Promise.all([timeout(100), timeout(200)]);
})

一旦 Promise 实例的状态改变以后,就可以使用then()方法指定下面将要执行的函数,catch()方法用来处理rejected状态的情况。

module

ES6 意义最重大的语法变化,就是引入了模块(module)。

一个模块内部,使用export命令输出对外的接口。

// lib/math.js
export function sum(x, y) {
  return x + y;
}
export var pi = 3.141593;

上面的模块输出了sumpi两个接口。

import命令用于引入该模块。

// app.js
import * as math from "lib/math";
alert("2π = " + math.sum(math.pi, math.pi));

上面代码中,*表示引入所有接口,也可以只引入指定的接口。

// otherApp.js
import {sum, pi} from "lib/math";
alert("2π = " + sum(pi, pi));
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值