【干货满满】前端框架及项目聚焦Vue/React/Webpack

1,784 阅读6分钟

一、webpack

1.1 什么是HappyPack

  • JS 单线程,开启多进程打包
  • 提高构建速度(特别是多核CPU)

使用 happyPack 多进程打包

    const HappyPack = require('happypack')
    
    // 步骤1 module.rules下-将对.js的文件交给id为label的HappyPack实例
    {
      test: /\.js$/,
      use: ['happypack/loader?id=babel']
    }
    
    // 步骤2 happyPack开启多进程打包
    new HappyPack({
     // 用唯一的标识符 id 来代表当前的HappyPack 是用来处理一类特定的文件
     id: 'babel',
     // 如何处理.js 文件,用法和Loader 配置一样
     loaders: ['babel-loader?cacheDirectory']
    })

1.2 ParallelUglifyPlugin 多进程压缩JS

  • webpack 内置 Uglify 工具压缩JS
  • JS单线程,开启多进程压缩更快
  • 和happyPack 同理
    // 使用 ParallelUglifyPlugin 并行压缩输出的 JS 代码
    const ParallelUglifyPlugin = require('ParallelUglifyPlugin')
    
    new ParallelUglifyPlugin({
      // 传递给 UglifyJS 的参数
      // (还是使用 UglifyJS 压缩,只不过帮助开启了多进程)
      uglifyJS: {
        output: {
          beautify: false, // 最紧凑的输出
          comments: false // 删除所有的注释
        },
        compress: {
            // 删除所有的 `console` 语句,可以兼容ie浏览器
            drop_console: true,
            // 内嵌定义了但是只用到一次的变量
            collapse_vars: true,
            // 提取出出现多次但是没有定义成变量去引用的静态值
            reduce_vars: true
         }
      }
    })

关于开启多进程

  • 项目较大,打包较慢,开启多进程能提高速度
  • 项目较小,打包很快,开发多进程会降低速度(进程开销)

1.3 webpack如何配置热更新

  1. 自动刷新:整个网页都刷新,速度较慢
  2. 自动刷新:状态会丢失(表单内数据会丢失)
  3. 热更新:新代码生效,网页不刷新,状态不丢失

HotModuleReplacementPlugin插件在webpack/lib下

// 配置 在entry中的index中
 index: [
    'webpack-dev-server/client?http://localhost:8080/',
    'webpack/hot/dev-server',
    path.join(srcPath, 'index.js')
 ]
 
 // 配置2
在plugins中new HotModuleReplacementPlugin()

// 配置3
在devServer加hot: true

// 配置4
业务中加module.hot来确定哪些范围需要触发热更新

二、 React

2.1 函数组件和 class 组件的区别

函数组件:

  1. 纯函数,输入props,输出JSX;
  2. 没有实例,没有生命周期,没有state;
  3. 不能扩展其它方法;

2.2 什么是React非受控组件

2.2.1 非受控组件

  1. ref
  2. defaultValue defaultChecked
  3. 手动操作DOM 元素

2.2.2 受控组件 vs 非受控组件:

-   优先使用受控组件,符合React设计原则(数据驱动视图);
-   必须操作DOM时,再使用非受控组件;

2.2.3 非受控组件-使用场景:

  1. 必须手动操作DOM元素,setState实现不了;
  2. 文件上传 <input type=file>(setState只能实现和前端显示渲染相关的,文件上传这种交互的是实现不了的)
  3. 某些富文本编辑器,需要传入DOM元素;

2.3 什么场景需要用React Portals

2.3.1 Portals:

  1. 组件默认会按照既定层次嵌套渲染;
  2. 如何让组件渲染到父组件以外?
定位为fixed的元素,有些情况需要把它放在body第一层去渲染,比如uc浏览器,或其它一些浏览器或环境,有更好的浏览器兼容性。

this.props.children  // 对应vue中的slot    这里值为"Modal 内容"
<PortalsDemo>Modal 内容</PortalsDemo>

// DOM操作需要引入ReactDOM
return ReactDOM.createPortal(
    <div className="modal">{this.props.children}</div>,
    document.body  // 第二个参数传入一个DOM 节点
)

2.3.2 Portals使用场景:

  1. overflow:hidden; // 父组件设了BFC,会限制子组件的布局,可以用Portals让子组件逃离父组件
  2. 父组件z-index值太小;
  3. fixed需要放在body第一层级
  • 虽然利用Portal可以把组件渲染到别的地方,但是它在React中的组件结构还是一样的。

2.4 是否用过React Context

  • 公共信息(语言、主题)如何传递给每个组件?
    1. 用props太繁琐
    2. 用redux小题大做,过度设计
生产:
//创建Context 填入默认值(任何一个js变量)
const ThemeContext = React.createContext('light') 

管理:
// 然后在最外层使用
<ThemeContext.Provider value = {this.state.theme}>
</ThemeContext.Provider>包裹起来
// 可以通过绑定的value修改默认值

消费:
class组件

在定义完组件class之后
//指定contextType读取当前的theme context
ThemedButton.contextType = ThemeContext 
另一种写法:(ES6新语法)
static  contextType = ThemeContext
这两种写法都是定义一个静态属性

//指定完之后通过this.context消费
// React会往上找到最近的theme Provider
const theme = this.context

2.5 React如何异步加载组件

  • 异步组件:(React一般用后两种)
    1. import()
    2. React.lazy
    3. React.Suspense
  • 使用
const ContextDemo = React.lazy( () => import('./ContextDemo') )

然后引用这个异步组件<ContextDemo>
异步加载过程中可能会出现等待的情况,可以使用React.Suspense包裹异步组件,fallback中定义一个标签或组件,用来在加载过程中的提示显示。

2.6 React性能优化-SCU的核心问题在哪里

  • shouldComponentUpdate (简称SCU)
  • PureComponent 和 React.memo
  • 不可变值immutable.js

2.6.1 SCU的基本用法

-   SCU默认值返回的是true(可以渲染),还给了我们返回false(不重复渲染)的可定制的权利
-   

2.6.2 React性能优化-SCU默认返回什么

在React的逻辑里面,如果没有做任何优化,只要父组件有更新,子组件也会无条件也进行更新,不管子组件的数据有没有变化。

如果没有定义SCU,SCU会默认返回true。
有些情况下,因为React的这个默认机制,而导致的性能问题,就需要在SCU中优化。

性能优化对于React更加重要!(react和vue的机制不一样)

SCU一定要每次都用吗?——不一定,需要的时候才优化

React性能优化-SCU一定要配合不可变值

2.6.3 如果setState没有遵循不可变值的原则:

  • 这里list数组push之后,list已经发生改变,当再setState时,前后两个的list值已经一样了。
  • 所以会造成SCU中的前后值判断相等,返回false,不会重新渲染。

2.6.4 SCU 使用总结

  • SCU 默认返回true,即React 默认重新渲染所有子组件
  • 必须配合“不可变值”一起使用
  • 可以先不用SCU,有性能问题时再考虑使用

2.7 React性能优化-PureComponent和memo

2.7.1 PureComponent(纯组件) 和 memo

  • PureComponent,SCU中实现了浅比较(也是需要配合不可变值的)
  • memo,函数组件中的PureComponent
  • 浅比较已适应大部分情况(尽量不要做深度比较)
  • class组件用PureComponent,函数组件用memo

2.7.2 PureComponent 的使用:

  • class List extends React.PureComponent{}
  • 相当于隐藏了一个SCU,里面进行了浅比较。

2.7.3 memo 的使用:

2.8 React性能优化-了解immutable.js

2.8.1 immutable.js:

  • 彻底拥抱“不可变值”;
  • 基于共享数据(不是深拷贝),速度好;
  • 有一定学习和迁移成本,按需使用;
const map1 = Immutable.Map({a:1,b:2.c:3})
const map2 = map1.set('b', 50)
map1.get('b') // 2
map2.get('b') // 50

2.9 什么是React高阶组件

2.9.1 关于组件公共逻辑的抽离:

    1. mixin,已被React弃用;
    1. 高阶组件HOC;(high order components)
  1. 透穿所有prps (接收的props 的值都 透传给子组件)(Vue $props v-bind)
  2. 增加mouse属性 <Component {...this.props} mouse={this.state}/>
    1. Render Props;

2.10 redux connect是高阶组件

  • 作用:连接React组件与 Redux store
mapStateToProps(state, ownProps) : stateProps
mapDispatchToProps(dispatch, ownProps): dispatchProps

  • connect 源码

Vue高阶组件 讲解传送门

2.11 什么是React Render Props

  • Render Props(只适用于React)
  • Mouse组件
  • App组件通过props接收a

2.12 HOC vs Render Props

  • HOC: 模式简单,但会增加组件层级
  • Render Props: 代码简洁,学习成本较高
  • 按需使用

2.13 Redux考点串讲

  • 和Vue 作用相同,但比Vuex 学习成本高
  • 不可变值,纯函数
  • 面试常考

Redux 使用

  1. 基本概念
  2. 单项数据流(画单向数据流图,经常考)
  3. react-redux(redux怎么连接react,考点不多,但要知道)
  4. 异步action(常考)
  5. 中间件(考察频率不高,但要知道)

相关内容

  • redux
    • store
    • reducer
    • action
    • dispatch
    • 单向数据流模型
    • 中间件redux-thunkredux-saga
  • react-redux
    • provider
    • connect
    • mapStateToProps
    • mapDispatchToProps
  • react-router

2.14 描述Redux单项数据流

Redux 中文文档>>>

单项数据流概述:
  • dispatch(action)
  • reducer -> newState
  • subscribe 触发通知

2.15 串讲react-redux知识点

react - redux:

  • <Provider>
  • connect
  • mapStateToProps mapDispatchToProps
通过react-redux插件引入Provider,Provider是一个react组件。

//createStore中传入的是reducer
let store = createStore(todoAPP)

//在Provider中传入store,这样里面的所有组件都有了store的能力
<Provider store={store}></Provider>

函数组件 AddTodo ,接收 props 参数
通过结构的写法,{dispatch} 即 props.dispatch

  • 在各个组件组件中想要消费redux的能力,需要把定义好的组件通过connect包裹一下,返回高阶组件。
  • connect 高阶组件,(connect 包裹组件之后,就已经)将 dispatch 作为 props 注入到 AddTodo组件中

2.16 React原理-考点串讲

2.16.1 再次回顾不可变值

2.16.2 vdom和diff是实现React的核心技术

  • vdom
    • h函数
    • Vnode 数据结构
    • patch 函数
  • diff 算法
    • 只比较同一层级,不跨级比较
    • tag不相同,则直接删掉重建,不在深度比较
    • tag 和 key,两者都相同,则认为是相同节点,不在深度比较

2.16.3 JSX本质是什么

  • JSX 等同于Vue 模板
  • Vue 模板不是html
  • JSX 也不是JS

babel:https://www.babeljs.cn

2.16.4 JSX 本质

  • React.createElement即h函数,返回vnode
  • 第一个参数,可能是组件,也可能是html tag
  • 组件名,首字母必须大写(React 规定)

2.17 说一下React的合成事件机制

2.17.1合成事件

  • 所有事件挂载到document 上
  • event 不是原生的,是SyntheticEvent 合成事件对象
    • (event 其实是React 封装)可以使用__proto__.constructor
  • 和Vue事件不同,和DOM事件也不同

2.17.2 为何要合成事件机制?

  • 更好的兼容性和跨平台
  • 载到document,减少内存消耗,避免频繁解绑
  • 方便事件的统一管理(如事务机制)

2.18 说一下React的batchUpdate机制

  • 有时异步(普通使用),有时同步(setTimeout, DOM事件)
  • 有时合并(对象形式),有时不合并(函数形式)
  • 后者比较好理解(像Object.assgin)

2.19 setState 异步还是同步?

  • setState 无所谓同步还是异步
  • 看是否命中batchUpdate 机制
  • 判断isBatchingUpdates

哪些能命中 batchUpdate 机制

  • 生命周期(和它的调用函数)
  • React 中注册的事件(和它调用的函数)
  • React 可以“管理”的入口

哪些不能命中 batchUpdate 机制

  • setTimeout setInterval 等(和它调用的函数)
  • 自定义的DOM 事件(和它调用的函数)
  • react "管不到"的入口

2.20 简述React事务机制

2.21 说一下React组件渲染和更新的过程

1. JSX本质和vdom

  • JSX 即createElement 函数
  • 执行生成vnode
  • patch(elem, vnode) 和 patch(vnode, newVnode)

2. 组件渲染过程

  • props state
  • render() 生成 vnode
  • patch(elem, vnode)

3. 组件更新过程

  • setState(newState) --> dirtyCompontents(可能有子组件)
  • render() 生成newVnode
  • patch(elem, newVnode)

2.22 React-fiber如何优化性能

1. patch 被拆分两个阶段

  • reconciliation 阶段 - 执行diff 算法,纯JS 计算
  • commit 阶段 - 将diff 结果渲染DOM

2. 可能会有性能问题

  • JS 是单线程,且和DOM 渲染公用一个线程
  • 当组件足够复杂,组件更新时计算和渲染都压力巨大
  • 同时再有DOM 操作需求(动画、鼠标拖拽等),将卡顿

3. 解决方案 fiber

  • 将 reconciliation 阶段进行任务拆分(commit无法拆分)
  • DOM 需要渲染时暂停,空闲时恢复
  • window.requestIdleCallback

4. 关于fiber

  • React 内部运行机制,开发者体会不到

2.23 React原理-总结

  • 函数式编程
  • vdom 和 diff
  • JSX 本质
  • 合成事件
  • setState batchUpdaet
  • 组件渲染过程
  • 前端路由

2.24 React真题演练-1-组件之间如何通讯

组件之间如何通讯

  • 父子组件 props
  • 自定义事件
  • Redux 和 context

JSX 本质是什么?

  • createElement
  • 执行返回Vnode

Context 是什么,如何应用?

  • 父组件向其所有子孙组件传递信息
  • 如一些简单的公共信息:主题色、语言等
  • 复杂的公共信息,请用redux

shouldCompontentUpdate 用途

  • 性能优化
  • 配合“不可变值”一起使用,否则会出错

redux 单向数据流

2.25 React真题演练-2-ajax应该放在哪个生命周期

setState 场景题

什么是纯函数

  • 返回一个新值,没有副作用(不会“偷偷”修改其他值)
  • 重点: 不可变值
  • 如:arr1 = arr.slice()

React 组件的生命周期

  • 单组件的生命周期
  • 父子组件的生命周期
  • 注意SCU

ajax应该放在哪个生命周期?

  • 同Vue
  • componentDidMount

渲染列表,为何使用key

  • 同Vue,必须使用key,且不能是index 和 rendom
  • diff算法通过tag 和 key 来判断,是否是sameNode
  • 减少渲染次数,提升渲染性能

2.26 React真题演练-3-组件公共逻辑如何抽离

函数组件和class 组件的区别

  • 纯函数组件,输入props,输出JSX
  • 没有实例,没有生命周期,没有State
  • 不能扩展其他方法

什么是受控组件

  • 表单的值,受State控制
  • 需要自行监听onChange,更新state
  • 对比非受控组件

何时使用异步组件

  • 同Vue
  • 加载大组件
  • 路由懒加载

多个组件有公共逻辑,如何抽离

  • 高阶组件(HOC)
  • render Props
  • mixin已被react 废弃

redux 如何进行异步请求

  • 使用异步action
  • 如redux-thunk

2.27 React真题演练-4-React常见性能优化方式

react-router 如何配置懒加载

pureCmpontent 有何区别

  • 实现了浅比较的shouldComponentUpdate
  • 优化性能
  • 但要结合不可变值使用

React 事件和DOM事件的区别

  • 所有事件挂载到document上
  • Event 不是原生的,是SyntheticEvent 合成事件对象
  • dispatchEvent

React 性能优化

  • 渲染列表时 key
  • 自定义事件、DOM事件及时销毁
  • 合理使用异步组件
  • 减少函数bind this的次数
  • 合理使用SCU PrueCompontent 和 memo
  • 合理使用Immutable.js
  • webpack 层面的优化
  • 前端通用的性能优化,如图片懒加载
  • 使用SSR

2.28 React真题演练-5-React和Vue的区别

  • 都支持组件化
  • 都是数据驱动视图
  • 都使用vdom 操作DOM
  • React 使用JSX拥抱JS,Vue使用模板拥抱html
  • React 函数式编程,Vue声明式编程
  • React 更多需要自力更生,Vue 把想要的都给你