Deep In React (一) 高性能React组件

React的渲染机制 在React内部,存在着初始化渲染和更新渲染的概念。 初始化渲染会在组件第一次挂载时,渲染所有的节点 当我们希望改变某个子节点时 我们所期望React帮我们实现的渲染行为是这样的 我们希望当我们的props向下传递时,只有对应需要更新的节点进行更新并重新渲染,其余节点不需要更新和重新渲染。 但是事实上,在默认的情况下,结果却是这样的 所有的组件树都被重新渲染,因为对于React而言,只要有props或者state发生了改变,我的组件就要重新渲染,所以除了绿色的节点,所有的黄色节点也被渲染了。 例子: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 const Foo = ({foo}) => { console.log('Foo is rendering!'); return (<div>Foo {foo}</div>); } const Bar = ({bar}) => { console.log('Bar is rendering!'); return (<div>Bar {bar}</div>); } const FooBarGroup = ({foo, bar}) => { console.log('FooBar is rendering!'); return ( <div> <Foo foo={foo} /> <Bar bar={bar} /> </div> ) } class App extends React.Component { constructor(props) { super(props) this.state = { foo: 0, bar: 0 }; this.handleFooClick = this.handleFooClick.bind(this); this.handleBarClick = this.handleBarClick.bind(this); } handleFooClick (e) { e.preventDefault(); const newFoo = this.state.foo + 1; this.setState({foo: newFoo}); } handleBarClick(e) { e.preventDefault(); const newBar = this.state.bar + 1; this.setState({bar: newBar}); } render() { const {foo, bar} = this.state; return ( <div className="App"> <button onClick={this.handleFooClick}>Foo</button> <button onClick={this.handleBarClick}>Bar</button> <FooBarGroup foo={foo} bar={bar} /> </div> ); } } ...

2018年10月17日 · 4 分钟 · hateonion

使用Typescript给JavaScript做静态类型检查

从迁移TypeScript说起 笔者所说的这个项目,是一个运行了接近五年的老项目,代码横跨es3到es6。而且代码风格由于项目的人员流动也各异。由于项目人数越来越多,以前留下的技术债造成的危害也越来越大。而重构,在这样一个臃肿且混乱的项目中显得举步维艰。由于JS的动态性,有的时候你甚至不知道这个方法是某个类下的实例方法还是JavaScript原生或是JQuery所提供的方法。 这个时候,TypeScript由于其提供的强类型能很好的规范代码,方便开发人员进行日常开发和重构,开始进入了我们的视野。 但是马上我们面对上了另一个难题,那就是,我们只想享受TypeScript强类型带来的类型推导的优势,并不想花大功夫去把整个代码库全部重构成TypeScript。 不过好在,TypeScript从2.3版本后就开始支持使用JsDoc的语法,以comment的形式给JavaScript文件提供强类型的支持。Type Checking JavaScript Files · TypeScript 如何开始使用Type Checking 首先你需要在你需要检查的JavaScript的文件头部显式的加上如下comment 1 // @ts-check 对变量进行类型检查 如果你需要声名一个变量的类型,你可以这样 1 2 3 4 5 /** @type {number} */ let x; x = 0; // OK x = false; // Error: boolean is not assignable to number 当你尝试给x赋一个bool值时,编辑器会提示你类型冲突。 对函数进行类型检查 当然某些时候我们最需要的其实是对于函数签名和返回值的强类型声名,以便我们在其他地方使用的时候不会传入错误的参数或者使用类型错误的函数返回值。TypeScript提供了三种语法来声名函数的类型. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 // jsdoc standard syntax // 声明一个函数 /** * @param {string} foo * @param {string} bar * @returns {string} */ function test(foo, bar) { return `${foo} and ${bar}` } // closure syntax // 声明一个函数表达式 /** * @type {function(string, string): string} */ let test; // test 必须符合定义的函数签名 test = (foo, bar, foobar) => '123' // 报错 函数不符合定义的签名 test = (foo, bar) => 1 // 报错 函数返回值不符合 // typescript like syntax // 声明一个函数表达式 /** * @type {(foo:string, bar:string) => string} */ let test; // test 必须符合定义的函数签名 在日常使用中,如果你想声明一个函数,对于函数做类型检查,你需要使用 @params @returns这种declaration 语法。 如果你想确定一个函数表达式的签名,你需要使用 @type的语法。 ...

2018年10月14日 · 4 分钟 · hateonion

使用Jest进行Javascript单元测试

什么是 Jest Jest 是 Facebook 推出的一款开源的前端测试框架,或者我更愿意称其为包含了断言库 / 测试框架 / Mock 框架 / CLI 的开箱即用的前端测试套件。 Jest 和其他测试框架的区别 如果将常用的前端单元测试所需要的工具做横向分隔的话,其实可以分为这么几个大类。 测试框架 运行环境 Mock 框架 断言库 覆盖率工具 Jasmine karma sinon.js chai Istanbul mocha should.js 我们常说的前端测试框架比如 Jasmine 或者 Mocha 其实某种程度上并不能独立的运行起来并且集成在我们日常的工作流之中。比如最常见的 Jasmine,Jasmine 基本上很难去脱离 Karma 去使用,并且 Jasmine 自带的断言和 Mock 有的时候也无法完全满足我们的需求,可能还需要搭配 Sinon.js 或者 chai,最后配合 Istanbul 进行覆盖率分析。在实际的工作中,当你想基于 Jasmine 去构建项目的测试框架时,实际上你会发现,你的绝大多数时间都花在了搭建这些工作链上。 磨刀不误砍柴工,但是磨刀的时间太久也会消耗技术人员的耐心和热情,让一件事情变得难以实施。 而 Jest 主打的就是其开箱即用的特性,只需要很少的配置就可以很方便的接入现有项目之中。如果你恰巧使用了creat-react-app 这个脚手架的话,那么恭喜你,脚手架已经自带了 Jest 集成。 ...

2018年7月18日 · 5 分钟 · hateonion