react设计模式与最佳实践 读书笔记
作者【意】米凯莱·贝尔托利 译者:林昊 阅读时间:2021.01.28 ~
第一章 React基础
- 关注点分离 2.React 声明式编程范式
- 命令式编程描述代码如何工作,而声明式编程则表明想要实现什么目的
- 声明式编程无需使用变量,也不用在执行过程中持续更新变量的值
- 使用声明式编程编程人员只需描述他们想要实现什么目的,而无需列出实现效果的所有步骤,最终代码会更简单,bug也会更少,可维护性会更强。
- 一致性比较:react调用组件时通过传入props来取回底层元素,再对返回结果递归的执行相同操作,直到取到完整的DOM节点数,将它渲染到屏幕上。
- 组件:元素的type是函数
- DOM节点:元素的type是字符串。
-
React最终目标:将创建组件所用到的每项技术都封装起来,并根据它们的领域和功能进行关注点分离。
-
React是个很小的库,分成了两个包:
- React: 实现了react库的核心特性(可以支持不同的目标平台:浏览器的React Dom、移动设备上的React Native)
- react-dom:包含了与浏览器相关的所有特性。
- 只引入核心包,则无法使用JSX语法,因为JSX不是浏览器支持的标准语言 (简单UI可使用createElement,复杂的就建议引入JSX转译器了)
- 如果应用较大,建议引入路由库来处理不同的页面和视图
- 应用扩增,需要利用外部依赖项对复杂操作进行抽象,此时应该引入“包管理器”
- 如果需要将应用拆分成独立的模块并按正确的形式组织文件,则应考虑使用模块打包器。
- 上述通过迭代增多项目依赖内容的方式,可避免学习新内容时的“疲劳感”
第二章 整理代码
JSX
- JSX react提供了两种定义元素的方式:一种是使用JavaScript函数,另一种是使用类似xml的jsx语法
- babel: 用来转义jsx和es2015(es6)后的语法(主流浏览器已经很好的支持了es2015,但更新的语法及特性支持程度不一,所以把js相关代码统一转译成es2015的版本后再执行)
- npm i --global babel-cli
- babel source.js -o output.js
- npm i --global babel-preset-es2015 babel-preset-react // 产入产出的预设方案
- 运行babel会把jsx 语法的
转换成 React.createElement('div')
- jsx创建html元素时以小写开头
- jsx与html的区别
- 保留字取代 className=class , htmlFor = for
- 样式 样式名写法由css字符串改为了驼峰式命名法
- 根元素 jsx会转换成JavaScript函数,而JavaScript函数不允许返回两个函数,因此多个同级元素必须封装在同一个父元素里
- 空格 html中标签换行会有空格,jsx没有
- 布尔值属性 jsx:声明即为true,html声明未赋值即为false
- 展开属性 来源于ecmaScript提案中的 对象剩余/展开属性(Object Rest/Spread Properties for ECMAScript)
- 向子元素传递数据时,不要按引用方式传递整个JavaScript对象,而要使用对象的基本类型值以方便校验,能够bug更少、更稳健。
Eslint
https://www.cnblogs.com/keepLeung/p/14363301.html
函数式编程基础
- 是一种声明式范式,避免代码副作用,推崇数据不可变,从而更易维护,可使代码更整洁
- 一等对象:可以赋值给变量,可以作为参数传给其他函数
- 高阶函数:接受一个函数作为参数(也可以是其他参数),通常添加一些增强的特殊行为,而后返回另一个函数作为返回值
- 纯函数:不产生副作用,也就是说他不会改变自身作用域以外的东西
// 纯函数
const add = (x,y)=>x+y
// 非纯函数
let x = 0;
const add1 = y => {x = x+y}
// 如果纯函数需要改变作用域以外的东西,可以通过返回值进行
let x = 0;
x = add(x,y) - 不可变性(一种操作数据的方式):函数式编程中,函数不会修改变量值,而是创建新的变量,赋值后再返回
// 未遵循不可变性
const add = arr=>arr.push(3)
const arr = [1,2]
add(arr) // [1,2,3]
add(arr) // [1,2,3,3]
// 遵循不可变性
const add = arr=>arr.concat(3)
const arr = [1,2]
const result1 = add(arr) // [1,2,3]
const result2 = add(arr) // [1,2,3] - 柯里化:将多参数函数转化为单参数函数,同时这些单参数函数的返回值也是函数
// 不柯里化
const add = (x,y)=>x+y;
// 柯里化
const add = x=>y=>x+y; - 组合:多个易于测试的纯函数、组件组合成一个 可以提供更高级功能的新函数
const add = (x,y)=>x+y;
const squre = x =>x*x;
const addAndSqure = (x,y)=>squre(add(x,y)) - 幂等函数: 传入相同的应用状态时返回同样的UI
第三章 开发真正可复用的组件
- 箭头函数会自动绑定this
- 用新状态调用setState时,对象会合并到当前状态上。
this.state={a:1}
this.setState({
b:2
})
// 最终的状态
{a:1,b:2}
应将setState看作异步的
- react知道如何优化事件处理器内部的状态更新,但无法优化执行过程:正常顺序取到旧值,setTimeout里取到新值
- React lumberjack用于调试应用的某个特殊状态
<script src="https;//unpkg.com/react-lumberjack@1.0.0"><script>
Lumberjack.back()
Lumberjack.forward()
- 只能将满足需求的最少数据放到状态中;触发事件时只应将需要更新的值添加到状态中
- 多个组件都需要使用同一份信息,应考虑使用应用层级的状态管理器,如redux
- 应避免使用状态的情况:
- 可派生的值(可通过props计算得到)
- 渲染方法
- props 可使用propTypes验证参数类型(只在开发模式下有效),更像ts,定义参数类型明确的接口
Button.propTypes = {
text: React.PropTypes.string.isRequired
}
- React Docgen 可配合propTypes生成文档
- 考虑多抽象一层以提高组件的可复用性
- storybook:已有组件列表服务
第四章 组合一切
- children的propTypes是array,如果只有一个的话会被优化成element
- 容器组件与表现组件模式,更清晰、更易维护。表现组件一般只包含ui,通常写为无状态的函数式组件
- mixin(已废弃)
- 解决的问题:不同组件共享功能
- 缺点:mixin内部函数不清楚,可维护性差;多个mixin定义或调用同一个函数型、状态中使用了属性名,会冲突;mixin相互依赖会导致耦合度增加、拓展困难
- 高阶组件(命名规范建议以with开头),将需要复用的部分作为被包裹组件的props传入,不影响被包裹组件的复用性。高阶组件不可滥用,每一层高阶组件都在添加新的渲染函数、生命周期方法、内存分配
- recompose(一个提供了许多高阶组件的库):flattenProp\renameProp\compose\getContext
- context:在组件树中传递数据
- 为避免组件context api与组件产生耦合,应使用高阶组件从context中获取数据,转换成props后再传递给组件
- 函数子组件,可动态的组合组件。优点如下:
- 可复用程度高,不需要关系子组件要接收什么
- 可以像高阶组件一样封装组件,但属性不需要固定,开发者可自行决定函数接收的变量名称
const Name = ({children})=>children('World')
Name.propTypes = {
children : React.PropTypes.func.isRequired,
}
// 调用Name
<Name>
{name=><div>Hello,{name}!</div>}
</Name>
第八章 服务端渲染(SSR, server-side rendering)的乐趣与益处
- 通用应用是什么? 应用的代码可以同时用于服务器和客户端
同构应用 :指应用在服务端和客户端看起来一模一样
-
启用服务器渲染的理由
-
用React创建简单的静态服务端渲染应用
-
了解服务端渲染的数据获取方式,并理解脱离和注回等概念
-
用Zeit开发的next.js 可以轻松创建同时在服务端和客户端运行的React应用
问题:
- 服务器渲染(可以开发通用应用)?
第十二章 未来的行动
- 为React做贡献
- 创建一个简单的示例 通过jsfiddl
- 提交问题 repoxx/issues/new
- fork整个仓库,编写代码解决问题,为补丁编写全面的测试,通过原有所有测试,避免引入新问题
- 发起pull request
- 开源的好处
- 他人可以受益,避免重复开发
- 可以提升自己的开发技能,遵循最佳实践
- 获得很多启发,他人思考的角度,甚至被帮助完善你的软件
- 获得与志同道合之人交流的机会
- 测试的重要性
- 代码更文件
- 帮助他人理解代码功能
- 有助于发现新增代码的缺陷
- 让参与编写代码的其他人员更有信心
- readme、lecense、react Storybook(文档)、示例都应该有
- 尽可能的减少样式、避免class、id名与实际项目冲突