All Posts

从 Flutter 源码看 InheritedWidget 内部实现原理

从 Flutter 源码看 InheritedWidget 内部实现原理

这两天学习了一下 Flutter 中的 InheritedWidget 的使用方法,顺便查看一下相关源码了解了其底层实现机制。特地记录一下。 Prerequirements 由于本文主要是从源码的角度分析 InheritedWidget 的工作原理,所以对阅读本文的小伙伴的 Flutter 知识有一定的要求。主要有以下几点,如果其中某部分你还不太清楚,请先阅读相关链接: 了解 Flutter 的基本用法。 了解 Flutter 中的 Widget 和 Element 的基本概念。 推荐阅读:Flutter, what are Widgets, RenderObjects and Elements? 对 Flutter 中 Element 的生命周期有基本了解。推荐阅读:Element class 下面开始正文。 InheritedWidget 的使用方法 先看一个 InheritedWidget 最简单的使用示例: import 'package:flutter/material.dart'; void main() => runApp(new MyApp()); class MyWelcomeInfo extends InheritedWidget { MyWelcomeInfo({Key key, this.welcomeInfo, Widget child}) : super(key: key, child: child); final String welcomeInfo; @override bool updateShouldNotify(InheritedWidget oldWidget) { return oldWidget.

Flutter 中 ListView 组件的子元素曝光统计

Flutter 中 ListView 组件的子元素曝光统计

在使用 Flutter 开发应用的过程中我们经常遇到需要展示一组连续元素的情景。这时我们通常会选择使用 ListView 组件。在电商场景中,被展示的元素通常是一组商品、一组店铺又或是一组优惠券信息。把这些信息正确的展示出来仅仅是第一步,通常业务同学为了统计用户的浏览习惯、活动的展示效果还会让我们上报列表元素的曝光信息。 什么是曝光信息? 什么是曝光是信息呢?简单来说就是用户实际看到了一个列表中的哪些元素?实际展示给用户的这部分元素用户浏览了多少次? 让我们通过一个简单示例应用来说明: import 'package:flutter/material.dart'; class Card extends StatelessWidget { final String text; Card({ @required this.text, }); @override Widget build(BuildContext context) { return Container( margin: EdgeInsets.only(bottom: 10.0), color: Colors.greenAccent, height: 300.0, child: Center( child: Text( text, style: TextStyle(fontSize: 40.0), ), ), ); } } class HelloFlutter extends StatelessWidget { final items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; @override Widget build(BuildContext context) { return ListView.

利用蓝灯为命令行配置HTTP代理

利用蓝灯为命令行配置HTTP代理

蓝灯是个好工具。可以帮忙我们访问一些由于众所周知的原因在国内无法正常访问的网站(比如 Google、Stack Overflow、Medium 等等)。 每次启动蓝灯,它会自动修改操作系统的网络代理指向它自己。不需要我们手动配置,很是方便。 需要网络代理的地方其实不止是浏览器,很多命令行工具也会访问网络。比如,我们通过 homebrew 安装 dart 的时候,brew 命令会从 Google 的服务器上下载安装文件。然后你就会看到网络连接错误的提示信息。 要解决这类问题,只需要为 Shell 设置两个环境变量 HTTP_PROXY 和 HTTPS_PROXY 即可。我们直接利用蓝灯在本地启动好的代理端口。 我们首先找到蓝灯在本地启动的具体端口号。打开蓝灯,依次选择 Settings -> ADVANCED SETTINGS 即可看到蓝灯在本地选择的端口号。 然后去 Shell 里执行以下两个命令设置环境变量: export HTTP_PROXY=http://127.0.0.1:51350 export HTTPS_PROXY=http://127.0.0.1:51350 就完成配置了。 最后为了避免每次都要敲这么长的命令,我们写一个 Shell 函数: # http proxy util hp() { if [ "$1" = "enable" ] then PORT="51350" if [ -n "$2" ] then PORT="$2" fi export HTTP_PROXY=http://127.0.0.1:$PORT export HTTPS_PROXY=http://127.0.0.1:$PORT else export HTTP_PROXY="" export HTTPS_PROXY="" fi } 把这都函数代码放到 Shell 启动脚本里。然后需要开启代理的时候执行 hp enable 即可,或是指定代理端口号 hp enable 33333。关闭代理执行 hp 即可。

Flutter 初体验

Flutter 初体验

初识 Flutter 还是在上个月的 GMTC 大会上。来自 Google 的工程师现场演示了如何使用 Flutter 构建美观、高性能的移动应用。个人对其中一些特性,比如良好的开发者体验、优秀的跨平台能力很感兴趣。于是决定在会后亲自体验一下。 最近几天尝试使用 Flutter 把京东 APP 中的排行榜频道的首屏布局实现了一下,算是对基于 Flutter 的开发有了一个最简单的了解,特地记录一下,方便其他想了解、尝试 Flutter 框架的小伙伴。 首先看看我实现了一个什么样的界面: 接下来让我们从不同方面说说 Flutter 的开发。 Flutter 开发环境搭建 安装 Flutter 不同平台的安装流程基本一致,这里就以 macOS 为例。首先下载 flutter macOS 版,并解压。 把 Flutter 的 bin 目录添加到系统 PATH 中: export PATH=~/Software/flutter/bin:$PATH 提示:记得把这行代码放到你的 shell 启动脚本中,避免每次都要手动执行。 路径添加完成后就可以执行 flutter 命令啦。 Flutter 提供了一个 flutter doctor 命令协助我们安装 Flutter 的依赖。它会检查本地是否有 iOS 和 Android 的开发环境。如果检测到依赖缺失,它还会给出对应依赖的安装方法。你只需要不断执行该方法,然后安装缺失的依赖,直到全部依赖安装完成即可。 配置代码编辑器 主要是给 IDE 安装相关插件。 VS Code 上只需要安装 flutter 扩展即可。 Android Studio 上需要安装 flutter 和 dart 两个插件。

利用 Jest 为 React 组件编写单元测试

利用 Jest 为 React 组件编写单元测试

图片来自 https://blog.algolia.com 在上一篇文章中我们介绍了什么是单元测试以及单元测试框架 Jest 的基本用法。在本文中我们会具体聊聊如何用 Jest 为 React 组件编写单元测试。 首先我们要明确的一点,那就是 React 组件的单元测试本质是也是单元测试。因此它也符合我们之前介绍过的单元测试的全部特点。唯一不同的地方在于 React 组件的单元测试中我们需要找到合适的方法对执行结果进行断言。换言之,我们要根据 React 的特点来设置代码是否正确执行的判断条件。 那么 React 组件和其它的被测试对象有何不同呢?仔细想过,我们会发现: React 组件的 render 结果是一个组件树,并且整个树最终会被解析成一个纯粹由 HTML 元素构成的树形结构 React 组件可以拥有 state,且 state 的变化会影响 render 结果 React 组件可以拥有生命周期函数,这些生命周期函数会在特定时间点执行 知道了要测试的内容,接下来的问题就是如何执行一个 React 组件并编写断言了。如何执行一个 React 组件呢?看到这个问题估计大多数儿人是蒙的。平时不就是直接 ReactDOM.render 吗?不错,ReactDOM.render 确实可以执行一个 React 组件并将它渲染到页面中,但这种方式不利于编写测试代码。 有没有更简单的方式呢?其实 React 已经帮我们提供好了工具,让我们一起来看看。 React 提供的测试工具 在 React 的官方文档中提到了两个用于测试 React 组件的库。让我们分别介绍。 react-test-renderer 在说 react-test-renderer 之前,让我们先聊聊什么是 renderer。React 最早是被用来开发网页的,所以早期的 React 库中还包含了大量和 DOM 相关的逻辑。后来 React 的设计思想慢慢被迁移到其它场景,最被人们熟知的莫过于 React Native 了。为了灵活性和扩展性,React 的代码被分拆为 React 核心代码与各种 renderer。React 自带了 3 个 renderer,前两个是大家常见的:

书写良好的 commit message

今天来说说如何书写好的 commit message。 Commit message 大家应该每天都在写,每次使用 Git 提交代码时,我们都会在执行 git commit 命令时附带上一句话来简要描述此次提交的改动。 Commit message 看似简单,作用却很重要。在阅读代码时,可以通过 commit message 了解到作者编写某行代码时的背景;调查 bug 时可以通过搜索 commit message 快速定位相关的提交记录。 那么什么样的 commit message 才算好的 commit message 呢? 开源社区已经为我们总结出了一套名为 Conventional Commits 的书写规范。很多流行的开源项目都使用了这套规范,如 Karma,Angular 等。其规定的格式如下: <type>[optional scope]: <description> [optional body] [optional footer] 下面我们分别来介绍一下其中的各个组成部分: type :用于表明我们这次提交的改动类型,是新增了功能?还是修改了测试代码?又或者是更新了文档?开源社区目前总结出了以下 11 种类型: build:主要目的是修改项目构建系统(例如 glup,webpack,rollup 的配置等)的提交 ci:主要目的是修改项目继续集成流程(例如 Travis,Jenkins,GitLab CI,Circle等)的提交 docs:文档更新 feat:新增功能 fix:bug 修复 perf:性能优化 refactor:重构代码(既没有新增功能,也没有修复 bug) style:不影响程序逻辑的代码修改(修改空白字符,补全缺失的分号等) test:新增测试用例或是更新现有测试 revert:回滚某个更早之前的提交 chore:不属于以上类型的其他类型 optional scope:一个可选的修改范围。用于标识此次提交主要涉及到代码中哪个模块。根据项目实际情况填写即可,最好在项目中规定好模块列表,保持一致性。

单元测试与单元测试框架 Jest

单元测试与单元测试框架 Jest

什么是单元测试? 测试是一种验证我们的代码是否可以按预期工作的手段。 被测试的对象可以是我们程序的任何一个组成部分。大到一个分为多步骤的下单流程,小到代码中的一个函数。 单元测试特指被测试对象为程序中最小组成单元的测试。这里的最小组成单元可以是一个函数、一个类等等。 单元测试的优势 由于被测试对象的简单(通常只有一个或多个输入以及一个输出),这就决定了单元测试开发起来也很简单,通常每个测试只有几行到十几行不等。测试代码的简单表示它可以被更频繁的执行(事实上,很多单元测试框架都有 watch 模式。每次改动代码时都会自动执行单元测试)。更频繁的执行意味着更早的发现问题。 试想,随着代码的不断迭代,程序中总有某些位置会频繁出现某类问题。在没有单元测试时程序员之间往往都是“口口相传”,隔一段时间很可能由于疏忽还会犯同一个错误。有了单元测试我们就可以为这些问题点编写对应的测试代码,每次提交代码前都执行一遍,可以极大的降低相同 bug 重复出现的概率。 此外,要为一个被测试对象编写单元测试,那么它应该首先是容易被测试的(这似乎是一句废话)。反过来讲,如果你面对一个函数、类却很难编写测试代码的时候,很可能是你的代码设计上存在问题。比如和外部依赖耦合过于紧密。这种情况下,编写单元测试的过程会倒逼我们优化我们代码的结构。将复杂的代码拆解成为更简单、更容易测试的片段。这个过程本身也会潜移默化的提高我们代码的质量。 单元测试的限制/不足 I get paid for code that works, not for tests - Kent Beck 首先,测试代码再简单,也是需要工作量来开发的。必定占用开发人员的时间。因此需要开发人员在投入与收益之间找到一个最佳的平衡点。 其次,单元测试覆盖率往往会给开发人员一种错觉:这段代码的单元测试都通过了(测试覆盖率以及 100% 了),肯定没有 bug。其实不然,单元测试覆盖率与代码质量没有必然的联系。作为开发人员必须尽早认识到这一点。 何时编写单元测试? 开发过程中,单元测试应该来测试那些可能会出错的地方,或是那些边界情况。 维护过程中,单元测试应该围绕着 bug 进行,每个 bug 都应该编写响应的单元测试。从而保证同一个 bug 不会出现第二次。 单元测试中的基本概念? 单元测试一般包含以下几个部分: 被测试的对象是什么 要测试该对象的什么功能 实际得到的结果 期望的结果 mock / spy (下文会详述) 具体到某个单元测试,往往包含以下几个步骤: 准备阶段:构造参数,创建 spy 等 执行阶段:用构造好的参数执行被测试代码 断言阶段:用实际得到的结果与期望的结果比较,以判断该测试是否正常 清理阶段:清理准备阶段对外部环境的影响,移除在准备阶段创建的 spy 等 Jest 简介 Jest 是 Facebook 开发的一款 JavaScript 测试框架。在 Facebook 内部广泛用来测试各种 JavaScript 代码。其官网上主要列出了以下几个特点:

是时候升级一下你的 nvm-windows 了

是时候升级一下你的 nvm-windows 了

一直以来都使用 nvm-windows 来管理 Node 版本。从没出过问题。今天团队小伙伴来反馈我们的一个内部命令行工具在 Node 6.10.0 上无法安装。于是决定安装一个 6.10.0 调查一下。 于是执行: nvm install v6.10.0 结果输出: $ nvm install v6.10.0 Node.js vv6.10.0 is not yet released or available. 似乎是哪里不对了。 于是下意识的 nvm ls available 一下看看: $ nvm ls available Showing the 15 latest available releases. STABLE | UNSTABLE --------------------------- v8.9.1 | v8.7.0 v8.9.0 | v7.9.0 v8.8.1 | v7.7.4 v8.8.0 | v7.7.3 v7.10.1 | v7.7.2 v7.10.0 | v7.7.1 v7.8.0 | v7.7.0 v6.12.0 | v6.

为 React 编写单元测试之一 —— 测试框架的选择

为 React 编写单元测试之一 —— 测试框架的选择

最近和小伙伴们在尝试做把项目中经常用到的 React 组件整理成一套 React 组件库。为了保证代码质量且方便日后维护,我们决定为组件编写单元测试。接下来几篇文章会聊聊在这个过程中我们遇到的问题以及一些思考。 正文开始 要写单元测试,首先面临的一个问题就是“我该使用哪个测试框架”? 如果你去 Google 上搜索“how to test react component”,在结果页面中你大概会来来回回看到以下几个名词/概念: Jest Enzyme Mocha全家桶(套餐内容大概率是:Mocha + Chai + Sinon + Istanbul) react-test-renderer react-dom/test-utils 首先让我们来看看这些库的功能和定位,然后再来做选择。 🃏 Jest Jest 是 Facebook 开发的一款 JavaScript 测试框架。在 Facebook 内部广泛用来测试各种 JavaScript 代码。其官网上主要列出了以下几个特点: 轻松上手 使用 create-react-app 或是 react-native init 创建的项目已经默认集成了 Jest 现有项目,只需创建一个名为 __test__ 的目录,然后在该目录中创建以 .spec.js 或 .test.js 结尾的文件即可 内置强大的断言与 mock 功能 内置测试覆盖率统计功能 内置 Snapshot 机制 虽然 Jest 官网介绍中多次 React,但实际上 Jest 并不是和 React 绑定的。你可以使用它测试任何 JavaScript 项目。

为 GitLab 代码库配置 Specific Runner

为 GitLab 代码库配置 Specific Runner

最近要为团队内一个项目搭建持续集成。项目代码托管在公司内部的 GitLab 上,于是很自然的选择使用 GitLab 自带的 CI/CD 功能。 在 GitLab 的 CI/CD 流程中具体执行任务的节点叫做 runner。GitLab 中有两种类型的 runner: Shared Runners 由 GitLab 管理员配置的公有 runner。多个项目公用。作为开发人员无需配置,可以直接使用。 Specific Runners 开发人员为每个代码库单独配置的专属 runner。只能执行所属代码库的任务。需要开发人员手动搭建。 由于我厂的 GitLab 并没有配置任何 Shared Runner。所以只能选择在自己的台式机上手动搭建。 具体流程如下: Step 1 下载 runner 可执行文件 根据你的环境下载 x86 或者 amd64 版本。 创建 D:\GitLab-Runner 目录,将刚刚下载好的文件复制到该目录并重命名为 gitlab-runner.exe。 Step 2 以管理员身份运行 Git Bash Step 3 访问代码库的配置页获取配置信息 进入代码库主页,依次点击 Settings => CI / CD => Runners settings。 这里展开的信息中有两个字段需要我们记下来。分别是一个 URL 和一个 Token。 Step 4 注册 runner 进入 D:\GitLab-Runner 目录执行命令: