小别致真东西
文章77
标签31
分类26
在 React 中使用 mobx 进行状态管理

在 React 中使用 mobx 进行状态管理

observable
inject
computed
action

autorun
RunInAction
Reaction

尽量使用箭头函数

调试

toJS 需要引入 => 不如直接 JSON.stringify()方便

不用使用数组索引或者任何将来可能会改变的值作为 key 。如果需要的话为你的对象生成 ids。

参考技巧

var array = [{name:'武汉'}, {name: '北京'}, {name:'上海'}, {name:'天津'}];
var resultArray = array.sort(
function compareFunction(param1, param2) {
return param1.name.localeCompare(param2.name,"zh");
}
);
console.log(resultArray);

根据现有的状态或其它计算值衍生出的值,响应式的产生一个可以被其它 observer 使用的值

import {observable, computed} from "mobx";

class OrderLine {
@observable price = 0;
@observable amount = 1;

constructor(price) {
this.price = price;
}
// computed 不支持箭头函数的写法
@computed get total() {
return this.price * this.amount;
}
}

想不产生一个新值,而达到一个效果,请使用 autorun。 举例来说,效果是像打印日志、发起网络请求等这样命令式的副作用。

autorun 中的值必须要手动清理才行

// 请求底部的 table Plan 绑定数据
@action fetchShopPlanList = (): ActionResponse => {
const [begin, end] = this.dateRange;
return http
.post(ApiBaseinfo_Admin_Restaurant_restaurantID_menuCalendarByDateRange, {
':restaurantID': globalStore.currentShopID,
begin,
end,
})
.then(({ error, data }) => {
if (error) {
return { error };
}

runInAction(() => {
const { menuCalendarList } = data;
// 遍历筛选绑定菜单项
this.boundObj = menuCalendarList.reduce((preObj, mealPlan) => {
const { color, name, date } = mealPlan;
if (color) {
preObj[`${date}_${name}`] = color;
}

return preObj;
}, {});
// 在一个请求的 action中直接去修改 state,可能会存在mobx 检测不到的情况,需要包裹 runInAction
this.shopCalendarList = data.menuCalendarList;
});

return { data };
});
};
VSCode 快捷键(持续更新)

VSCode 快捷键(持续更新)

文档编辑中键盘快捷方式

光标移动

  • 快速移动光标(按单词跳: option <- ->
  • 行首行尾移动光标 : command <- ->
  • 移动到文件头尾: commad <- -> 上下方向键

选中

  • 选中操作: shift <- -> 方向键操作选中方向
  • 选中光标所在单词: command D

其它

  • 搜索时切换搜索结果: shift Enter
  • 文件相对路径: shift command H 原shortCut => 自定义 command H
  • 新建未命名文件: command N
  • 搜索光标所在单词: command E
  • 跳转到指定行: ctrl + G
  • 选中所在的代码块(select Bracket),对花括号的代码块较友好: option command B
  • 切换tab: option commmad ⬅️/➡️
  • 删除整个单词: option backspace
  • 向上下复制整行: option shift ⬆️/⬇️ 上下方向键
  • 找到当前文件所有与选中相同的文档 达到批量修改的目的(change all ocurrences): shift command I
classnames 的用法总结

classnames 的用法总结

React 和 Vue class对比

在React项目开发中,类名的管理不像 Vue 那么方便;

如何为组件添加 CSS 的 class?
传递一个字符串作为 className 属性:

render() {
return Menu
}
CSS 的 class 依赖组件的 props 或 state 的情况很常见:

render() {
let className = ‘menu’;
if (this.props.isActive) {
className += ‘ menu-active’;
}
return Menu
}

在官方的提示下推荐开发者使用 classnames npm 包来管理自己的类名会方便很多

(function () {
'use strict';
// => Object.hasOwnProperty 用于判断某个成员是否在对象内
var hasOwn = {}.hasOwnProperty;
function classNames () {
// 存储 className 值
var classes = [];

// 循环实参, arguments就是实际调用函数传入的参数,类似数组
for (var i = 0; i < arguments.length; i++) {
// 获取实参value
var arg = arguments[i];

// 跳过false条件 => false, null, undefined, NaN, 空, ...
if (!arg) continue;

// 判断传入参数的类型
var argType = typeof arg;

// 如果参数的类型是 string 或者 number
if (argType === 'string' || argType === 'number') {
// 直接追加到classes数组后面
classes.push(arg);

// 如果参数是数组并且长度大于0
} else if (Array.isArray(arg) && arg.length) {
// 调用自身函数,利用apply可以将数组转成字符串
var inner = classNames.apply(null, arg);

// 现在是一个字符串,隐士判断布尔值
if (inner) {
// 追加到数组后面
classes.push(inner);
}
// 如果传入的参数是对象
} else if (argType === 'object') {
// 对object进行遍历
for (var key in arg) {
// 判断key是否存在arg对象内并且key的值隐士转换为true
if (hasOwn.call(arg, key) && arg[key]) {
// 将值追加到classes数组后面
classes.push(key);
}
}
}
}
// 将数组连接成字符串以空格拼接 => a b c
return classes.join(' ');
}

// 如果是node.js环境运行
if (typeof module !== 'undefined' && module.exports) {
classNames.default = classNames;
module.exports = classNames;

// 如果用的requirejs模块管理 AMD
} else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
define('classnames', [], function () {
return classNames;
});

// 否则运行于浏览器环境
} else {
window.classNames = classNames;
}
}());

classnames github库

React-router V4

React-router V4

React 创建的单页应用中、通过路由来控制页面间的跳转,常用的就是 react-router、react-router-dom

React Router中有三类组件

  • 路由组件 BrowserRouter, HashRouter
  • 路由匹配组件 Route, Switch
  • 导航、链接组件 Link

基于 React Router 的 web 应用,根组件应该是一个 router 组件(BrowserRouter,HashRouter )。 项目中,react-router-dom 提供了和两种路由。两种路由都会创建一个 history 对象。如果我们的应用有服务器响应 web 的请求,我们通常使用组件; 如果使用静态文件服务器,则我们应该使用组件 通常都是使用

Demo

Link 组件最终会渲染为 HTML 标签 ,它的 to、query、hash 属性会被组合在一起并渲染为 href 属性。虽然 Link 被渲染为超链接,但在内部实现上使用脚本拦截了浏览器的默认行为,然后调用了history.pushState 方法

Axios

Axios

先从fetch讲起

一个简单的fetch例子如下:

fetch('./api/person.json')
.then(
function(response) {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' +
response.status);
return;
}

// Examine the text in the response
// 将返回数据 Json 化
response.json().then(function(data) {
console.log(data);
});
}
)
.catch(function(err) {
console.log('Fetch Error :-S', err);
});

1. .json()返回一个被解析为JSON格式的`promise`对象,当获取成功时,我们使用 json() 读取并解析数据

E2E 测试

E2E 测试

概念

E2E 测试: 端到端测试(end to end)属于黑盒测试,是站在用户的角度进行的测试,自动化模拟用户在 UI 界面上的每一个操作(输入、点击、跳转等),确保整个操作流程顺畅且符合预期。

公司的小程序的 e2e 测试工作也已经完成一段时间了,最近项目新增页面也对应增加里测试代码。手头有时间最重要的是有心情,开始回顾一下整个小程序测试工作流程。 小程序的测试对于我来说还是一个全新的领域,接到要着手对手里的项目补充测试用例的工作安排马上开始着手调研小程序的 e2e 测试方案。

首先开始看小程序官方自动化文档,在文档的描述里面明确指出小程序的自动化不提供测试框架(所以还需要选一个相配套的测试框架, 决定选用 jest),只是提供了小程序开发工具的自动化 SDK,也支持通过远程调试控制真机测试(调用后脚本会启动工具真机调试功能,并且在控制台上打印二维码,然后你需要使用真机扫码连接使自动化脚本继续跑下去)。

官方的 SDK 中的 API 主要包括三大模块:

  • Automator 开发工具相关,提供连接及启动开发工具的方法
  • MiniProgram 小程序相关,提供控制小程序的方法(跳转、系统信息等),相当于开发中的 wx 对象
  • Page 页面相关,获取页面路由、数据、元素及元素属性、节点选择等
  • Element 页面节点选择、属性、事件等

从中可以看出该 SDK 提供了小程序测试中的基础: 操作开发工具、页面跳转、选取页面 && 节点对象、事件操作等
但是还缺少一些断言语句及其他更多能力
官方脚本示例:

const automator = require('miniprogram-automator')

describe('index', () => {
let miniProgram
let page

beforeAll(async () => {
miniProgram = await automator.launch({
projectPath: 'path/to/miniprogram-demo'
})
page = await miniProgram.reLaunch('/page/component/index')
await page.waitFor(500)
}, 30000)

afterAll(async () => {
await miniProgram.close()
})
})

测试

参考链接

小程序自动化

小程序自动化SDK为开发者提供了一套通过外部脚本操控小程序的方案,从而实现小程序自动化测试的目的。

通过该 SDK,你可以做到以下事情:

  • 控制小程序跳转到指定页面
  • 获取小程序页面数据
  • 获取小程序页面元素状态
  • 触发小程序元素绑定事件
  • 往 AppService 注入代码片段
  • 调用 wx 对象上任意接口

安装小程序自动化SDK:

npm install miniprogram-automator --save-dev
  1. 新功能不需要急着写AT,应该交给QA人肉测试,待功能上线后再慢慢补齐
  2. 反28原则: 28原则是指最重要的只占其中一小部分,约20%,其余80%尽管是多数却不重要,但是写AT需要反过来,我们优先写那80%不常用到的功能,至于那重要的20%,由于经常被使用,它能不能工作一目了然,其实也是最健壮的,需要写AT来覆盖的优先级就不显得这么高了,反而那不常用的80%功能往往没有经过大量的用户测试,很容易在某次迭代中产生新的bug。
  3. 优先写happy path,优先保证一个功能模块的主线畅通,再写边界值测试。
数组

数组

数组

定义:

一个存储元素的线性集合, 元素可以通过索引(通常为数字)来任意存取。

数字索引在内部被转换为字符串类型、这是因为在javaScript中对象的属性名必须是字符串。而数组只是一种特殊的对象

创建数组

  • 通过构造函数
    <!-- 传入一组元素进行数组初始化 -->
    var arr = New Array(1, 2, 3, 4, 5);
    print(arr.length); // 5
    <!-- 只传一个元素,声明数组的初始化长度, 其中每个元素初始化为 undefined -->
    var arr1 = new Array(10);
    print(arr1.length); // 10
同一台电脑配置多个SSH

同一台电脑配置多个SSH

配置多个SSH

在工作中多访问公司的gitlab仓库,而在生活中又有自己的github仓库
记录一下方便日后查找


一般电脑中的SSH key 存放在 ~/.ssh目录中 如果有配置过的话存在 id_rsa \ id_rsa.pub 私钥和公钥, 将公钥配置到需要的代码平台

生成SSH key

本地配置多个ssh key

  • 1、为公司生成一对秘钥ssh key

    ssh-keygen -t rsa -C 'yourEmail@xx.com' -f ~/.ssh/gitlab_id_rsa
  • 2、为github生成一对秘钥ssh key

    ssh-keygen -t rsa -C 'yourEmail2@xx.com' -f ~/.ssh/github_id_rsa
  • 3、在~/.ssh目录下新建名称为config的文件(无后缀名)。 用于配置多个不同的host使用不同的ssh key,常用内容如下:

    # gitlab
    Host gitlab.planetmeican.com
    HostName gitlab.planetmeican.com
    Port 2345
    User git
    PreferredAuthentications publickey
    IdentityFile ~/.ssh/gitlab_id_rsa
    # github
    Host github.com
    HostName github.com
    PreferredAuthentications publickey
    IdentityFile ~/.ssh/github_id_rsa

配置文件参数

# Host : Host可以看作是一个你要识别的模式,对识别的模式,进行配置对应的的主机名和ssh文件
# port: 端口号,一般不需要配置
# HostName : 要登录主机的主机名
#PreferredAuthentications: 授权验证方式
# User : 登录名
# IdentityFile : 指明上面User对应的identityFile路径
  • 4、分别往gitlab和github上添加生成的公钥

ssh-agent 与 SSH的区别

参考链接

react-redux中Provider、connect

react-redux中Provider、connect

react-redux中Provider

详情

Git 笔记

Git 笔记

Git 常用的命令笔记

Commitizen是一个撰写合格 Commit message 的工具。

本地分支重命名

git branch -m old new