React实战进阶学习笔记

以组件的方式构建UI

  • 受控组件:表单元素状态由使用者维护,一定有value和onChange属性
  • 非受控组件:表单元素状态由DOM自身维护,外部方法才能获得表单元素的值

创建组件的原则

  • 单一职责原则
    每个组件只做一件事情
    如果组件变得复杂,就应该拆分小组件:可以提高性能,当数据变化时,复杂大组件可能会整体刷新,而拆分后部分小组件如果没有变化则不用刷新。
  • 数据状态管理:DRY原则
    1. 能计算得到的状态不要单独存储
    2. 组件内尽量无状态,所需数据通过props获取:纯组件性能更好,更容易被重用

React的生命周期

image.png
  • constructor
    JS类的构造函数。可以在这个函数中初始化组件内部的状态,实际中很少使用;唯一可以直接修改state的地方。
  • getDerivedStateFromProps
    当state需要从props初始化得到时使用;
    尽量不要使用:维护state和props的一致性会增加复杂度;
    每次render都会调用;
    典型场景:获取表单输入的默认值
  • componentDidMount
    UI渲染完后只执行一次;
    典型场景:获取外部资源
  • getSnapshotBeforeUpdate
    在render之前调用,此时state已经更新;
    典型场景:获取render之前的DOM状态
  • shouldComponentUpdate
    决定Virtual DOM是否要重绘;
    一般可以由pureComponent自动实现(看之前的state、props和之后的state、props是否一致);
    典型场景:性能优化;

理解Virtual DOM及key的作用

diff算法
react的diff算法把传统的完全diff的O(n^3)复杂度优化为了O(n),是一种广度优先的分层算法
1.当同层的节点顺序发生变化时,根据节点的key来判断顺序变化,并更换节点顺序;
2.当同层的节点没有被同层引用,则直接删除节点
对于这种设计方式较为合理,因为节点出现跨层移动的概率较低。

虚拟DOM的两个假设:
1.组件的DOM结构相对稳定(即节点出现跨层移动的概率较低)
2.类型系统的兄弟节点可以被唯一标识(即节点的key)
如果没有key,可能会使得diff算法更新的方式性能开销更大

高阶组件和函数作为子组件:组件使用的一种新设计模式

  • 高阶组件
    高阶组件就是对原有的组件进行处理,如加入新的属性、方法等。高阶组件的入参为组件,出参为处理之后的组件。它可以用来处理组件之间的一些通用逻辑,但是自身并不包含任何UI展现。
  • 函数作为子组件
    是一种设计模式。组件的this.props.children(this.props.value)可以执行复用这个组件时里面定义的不同的函数。


    image.png

    因此,复用「函数作为子组件」的组件可以具体render的内容可以由组件传入的函数决定,而不是组件本身不断增加自己的功能。这使得组件的灵活性增大。

Context API及其使用场景

解决组件通信的问题。当context数据发生变化时会通知consumer进行数据刷新,而不用用forceUpdate在数据变化后手动执行强制刷新。


image.png

使用场景:全剧更新theme或language等

使用脚手架工具创建react应用

  • 为什么需要脚手架工具
    当创建一个react项目时,往往需要很多别的工具,比如redux管理数据状态、babel将ts等语言转换为浏览器可以识别的语言、webpack进行打包、eslint作为代码校验等,因此在最初开始一个react往往有着比较繁杂的步骤,但是这些步骤在每一次创建时往往都是重复的,仅仅需要改一些配置即可。因此诞生了脚手架工具。

打包和部署

  • 为什么需要打包
    编译ES6语法特性,编译JSX;
    整合资源,例如图片、scss等;
    优化代码体积;
  • 打包注意事项
    设置nodejs环境为production;
    禁用开发时专用代码;
    设置应用根路径;

Redux:JS状态管理框架

传统上state转换为DOM是在组件内部发生的;
redux则是把这个转换转移到了组件外,它提供一个全局唯一的store,这个store负责提供应用程序所有的state。是一个树形结构,和组件的树形结构是映射状态。redux也是为了让组件通信更便捷。

redux的三个特性

image.png

如上图,Single Source of Truth让数据state更容易追踪;
image.png

如上图,state发生变化一定是由action引起的;
image.png

如上图,纯函数是不引用外部任何变量或方法的函数;

深入理解Store、Action、Reducer

image.png

action是描述行为的数据结构;
一个reducer是一个函数,所有的reducer会接收到所有的action,一个action通过store dispatch出去,系统中定义的reducer都能接收到,而要不要执行则通过action.type决定。reducer执行后是直接返回新的state对象,而不是修改原有的state,否则store无法监听到变化;
image.png

工具函数

  • bindActionCreators
    一个可以封装dispatch具体action的工具函数,让action的dispatch动作可以在任何地方被调用;
  • combineReducers
    createStore要接收reducer来初始化,而combineReducers就是把多个reducer组合成一个新的reducer传给createStore,并定义每个reducer对应的state节点。

在react中使用redux

react和redux通过一个函数connect连接起来:

image.png

使用步骤
1.通过mapStateToProps定义组件需要访问store中的哪些属性;
2.通过mapDispatchToProps定义组件需要哪些dispatch操作来更改state值;
3.调用connect方法并使用;

理解异步Action和Redux中间件

image.png

异步Action
异步Action是一种设计模式,不是一种特殊的Action,而是几个Action的组合使用。如上图,当用户在点击View中的一个按钮时,会调用Ajax请求,这是的Action不是单纯的数据结构,而是一个请求,此时Middleware会截获这个请求,分别dispatch一些不同阶段的action。
Middleware
有两种:截获action、发出action

React Router:路由不止是页面切换,更是代码组织方式

  • 为什么需要路由?
    单页应用需要进行页面切换;
    通过URL可以定位到页面;
    更有语义地组织资源;


    image.png
  • 三中路由实现方式
    URL路由;
    hash路由(为了兼容低版本浏览器);
    内存路由;
  • 基于路由配置进行资源组织
    实现业务逻辑的松耦合;
    易于扩展、重构和维护;
    路由层面实现lazy load;

前端项目的理想架构

  • 易开发
    开发工具是否完善;
    生态圈是否繁荣;
    社区是否活跃;
  • 可扩展
    增加新功能是否容易;
    增加新功能是否会显著增加系统的复杂度;
  • 易维护
    代码是否容易理解;
    文档是否健全;
  • 易测试
    功能的分层是否清晰;
    副作用少;
    尽量使用纯函数;
  • 易构建
    使用通过技术和架构;
    构建工具的选择;

拆分项目复杂度:按领域模型(feature)组织代码,降低耦合度

按业务逻辑讲项目拆分成高内聚低耦合的模块;

  • 从技术角度划分目录
    1.按feature组织components、action和reducer;
    2.使用root loader加载每个feature下的各个资源;

你可能感兴趣的:(React实战进阶学习笔记)