前端技术总结七:React

1、Hooks

什么是Hooks

Hooks是一个新的React特性提案,组件尽量写成纯函数,如果需要外部React特性(比如状态管理,生命周期),就用钩子把外部特性"钩"进来,通常函数名字都是以use开头。首次在v16.7.0-alpha版本中添加。

Hooks产生的背景

组件之间复用状态逻辑很难,在hooks之前,实现组件复用,一般采用高阶组件和 Render Props,它们本质是将复用逻辑提升到父组件中,很容易产生很多包装组件,带来嵌套地狱。

组件逻辑变得越来越复杂,尤其是生命周期函数中常常包含一些不相关的逻辑,完全不相关的代码却在同一个方法中组合在一起。如此很容易产生 bug,并且导致逻辑不一致。

复杂的class组件,使用class组件,需要理解 JavaScript 中 this 的工作方式,不能忘记绑定事件处理器等操作,代码复杂且冗余。除此之外,class组件也会让一些react优化措施失效。

针对上面提到的问题,react团队研发了hooks,它主要有两方面作用:

用于在函数组件中引入状态管理和生命周期方法
取代高阶组件和render props来实现抽象和可重用性

 

2、纯函数

纯函数的定义是

1)如果函数的调用参数相同,则永远返回相同的结果。它不依赖于程序执行期间函数外部任何状态或数据的变化,必须只依赖于其输入参数。

2)该函数不会产生任何可观察的副作用,例如网络请求,输入和输出设备或数据突变(mutation)。

使用纯函数的原因:

是方便测试以及重构。纯函数还使得维护和重构代码变得更加容易,不必担心其副作用。正确地使用纯函数可以产生更加高质量的代码。

3、副作用

一个可以被观察的副作用是在函数内部与其外部的任意交互。这可能是在函数内修改外部的变量,或者在函数里调用另外一个函数等。
注: 如果纯函数调用纯函数,则不产生副作用依旧是纯函数。
副作用来自,但不限于:
1)进行一个 HTTP 请求
2)Mutating data
3)输出数据到屏幕或者控制台
4)DOM 查询/操作
5)Math.random()
6)获取的当前时间

4、useCallback

函数式组件中,每一次更新状态,自定义的函数都要进行重新的声明和定义,如果函数作为props传递给子组件,会造成子组件不必要的重新渲染,有时候子组件并没有使用到父组件发生变化的状态,此时可以使用useCallback来进行性能优化,它会为函数返回一个记忆的值,如果依赖的状态没有发生变化,那么则不会重新创建该函数,也就不会造成子组件不必要的重新渲染。

import React, { useState, useCallback, memo } from 'react'
const AddBtn = memo((props)=>{ // 使用函数表达式的方式定义了一个函数式组件
    return<button onClick={props.increment}>+1</button>
})

export default function CallBackPerformance(){
    const [ count, setCount ] = useState(0)
    const [ show, setShow ] = useState(true)
    const increment1 = () => {
        console.log('increment1被调用了')
        setCount(count+1)
  }

   const increment2 = useCallback(()=>{  // 使用了useCallback来优化的函数
         console.log('increment2被调用了')
         setCount(count+1)
    },[count])

    return(<div>
            <div>当前计数:{count}</div>
            <AddBtn increment={increment1} name="1"/>
            <AddBtn increment={increment2} name="2"/>
            <button onClick={e => setShow(!show)}>切换show</button>
        </div>)
}
// 当show这个状态发生变化时,子组件increment1会重新渲染,increment2不会重新渲染

 

5、useMemo

useMemo也是返回一个记忆的值,如果依赖的内容没有发生改变的话,这个值也不会发生变化,useMemo与useCallback的不同点在于useMemo需要在传入的函数里需要return 一个值,这个值可以是对象、函数

 

6、高阶函数

接受一个或多个函数作为输入;
或者输出一个函数;

 

7、高阶组件

高阶组件是参数为组件,返回值为新组件的函数

高阶组件本身不是一个组件,而是一个函数;
参数是一个组件,返回值也是一个组件

优点:

1.实现了对原有组件的增强和优化,
2.可以对原有组件中的state, props和逻辑执行增删改操作, 一般用于代码重用和组件增强优化

应用场景:

1、需要代码重用时, react如果有多个组件都用到了同一段逻辑, 这时,就可以把共同的逻辑部分提取出来,利用高阶组件的形式将这段逻辑整合到每一个组件中, 从而减少代码的逻辑重复
2、需要组件增强优化时, 比如我们在项目中使用的组件是第三方的,组件可能比较复杂, 有时不能完全满足需求, 但第三方组件不易修改, 此时也可以用高阶组件,在不修改原始组件的前提下, 对组件添加满足实际开发需求的功能
3、针对优点的应用
4、也可以用来替换 mixins 混入

 

8、函数组件和类组件

函数式组件和类组件的区别

1. 语法上的区别:

函数式组件是⼀个纯函数,它是需要接受props参数并且返回⼀个React元素就可以了。类组件是需要继承React.Component的,⽽且class组件需要创建render并且返回React元素,语法上来讲更复杂。

2. 调⽤⽅式:

函数式组件可以直接调⽤,返回⼀个新的React元素;类组件在调⽤时是需要创建⼀个实例的,然后通过调⽤实例⾥的render⽅法来返回⼀个React元素。

3. 状态管理:

函数式组件没有状态管理,类组件有状态管理。

4. 使⽤场景:

类组件没有具体的要求。函数式组件⼀般是⽤在⼤型项⽬中来分割⼤组件(函数式组件不⽤创建实例,所有更⾼效),⼀般情况下能⽤函数式组件就不⽤类组件,提升效率。

 

9、为什么state值不能直接修改,需要通过setState

setState 是异步的。是否调⽤ render 进⾏再次渲染。 setState 本质是通过⼀个队列实现 state 更新的,执⾏ setState 时,会将要更新的 state 合并后放⼊状态队列, ⽽不会⽴即更新。如果没有通过 this.setState, ⽽是直接 this.state 修改,会导致这个修改没有放⼊队列中,下次执⾏ this.setState 合并队列时,就会忽略这次的修 改,从⽽导致数据没有更新。 简单点说,就是 setState 就是放⼊队列,⽽ this.state 会跳过队列,从⽽导致有可能这次的修改值会被忽略掉

10、react的钩⼦函数有哪些?请求放在那个函数中?为什么?渲染页⾯钩⼦函数的执⾏顺序什么?

钩⼦函数: componentWillMount 、 render 、 componentDidMount 、 shouldComponentUpdate 、 componentWillUpdate 、 componentDidUpdate

请求放在:componentDidMount ,因为这个在组件加载的时候只会执⾏⼀次

执⾏顺序:componentWillMount 、 render 、 componentDidMount 、 shouldComponentUpdate 、 componentWillUpdate 、 render 、 componentDidUpdate componentWillReceiveProps 是在 props 发⽣改变的时候执⾏

11、state与props有什么区别?

props 是外部组件传⼊的数据,⼀般是⽗组件传到⼦组件的数据。 props ⾥⾯的数据不能修改,只能通过绑定⽗组件的⽅法来修改 props ⾥⾯的值,然后再传到⼦组件。 ⽽ state 是组件的私有变量。主要⽤于组件的保存,控制以及修改⾃⼰的状态,不能通过外部的访问以及修改,只能通过内部的 this.setState ⽅法来修改 state ⾥⾯的内容。

12、react如何去操作dom的?

通过 refs 可以实现对 dom 的操作。通过给组件添加 ref=‘XXXXX’, 然后在⽅法⽴马通过调⽤ this.refs.XXXXX ,从⽽进⾏对 dom 的操作

13、react在setState之后执⾏了哪些操作?

setState 的基本过程是,在执⾏ setState 之后,会执⾏ shouldComponentUpdate 、 componentWillUpdate 、 render 、 componentDidUpdate 。在执⾏ render 的时候this.state 才会被更新。之前两个钩⼦函数都不会更新

14、react性能优化是哪个周期函数?

shouldComponentUpdate 这个函数⽤来判断是否需要调⽤ render ⽅法重新描绘 dom ,因为 dom 的描绘⾮常的消耗性能,如果可以在 shouldComponentUpdate 中写出更优化的 dom diff 算法可以极⼤的提⾼性能

15、Diff算法

由于在浏览器中操作DOM是很昂贵的,频繁的操作DOM,会产生一定的性能问题,这就是虚拟DOM的产生原因。

虚拟DOM本质上是JavaScript对象,是对真实DOM的抽象状态变更时,记录新树与旧树的差异,最后把差异更新到真正的DOM中。

diff算法的作用:用来修改DOM的一小段,不会引起dom树的重绘

更高效的Diff算法:

React的开发者结合Web界面的特点做出了两个大胆的假设,使得Diff算法复杂度直接从O(n^3)降低到O(n),假设如下:

(1)两个相同组件产生类似的DOM结构,不同的组件产生不同的DOM结构;
(2)对于同一层次的一组子节点,它们可以通过唯一的id进行区分。

新的Diff算法是逐层进行比较,只比较同一层次的节点,不会跨层次比较,大大降低了复杂度。

不同类型节点的比较:Diff算法会直接删除旧的节点及其子节点并插入新的节点

相同类型节点的比较:若是两个节点类型相同时,Diff算法会重新设置该节点的属性,从而实现节点的更新。

 

16、redux

redux的基本思想是整个应用的state保持在单一的store中。

三大原则:

1、单一数据源
2、State 是只读的
3、使用纯函数来执行修改

 

store:store就是一个javascript对象,保存整个应用的state。

1、允许通过getState()访问state
2、通过dispatch(action)改变state
3、通过subscribe(listener) 注册listener
4、通过subscribe(listener) 返回函数处理listener的注册

action:是一个javascript对象,必须有个type属性表明正在执行action的类型。

{ type: 'ADD_TODO', text: 'Go to swimming pool' }

reducer:是一个纯函数,已先前的state和action作为参数,并返回下一个state。

dispatch:store.dispatch() 将 action 传到 store。

import { createStore } from 'redux';

/**
 * 这是一个 reducer,形式为 (state, action) => state 的纯函数。
 * 描述了 action 如何把 state 转变成下一个 state。
 *
 * state 的形式取决于你,可以是基本类型、数组、对象、
 * 甚至是 Immutable.js 生成的数据结构。惟一的要点是
 * 当 state 变化时需要返回全新的对象,而不是修改传入的参数。
 *
 * 下面例子使用 `switch` 语句和字符串来做判断,但你可以写帮助类(helper)
 * 根据不同的约定(如方法映射)来判断,只要适用你的项目即可。
 */
function counter(state = 0, action) {
  switch (action.type) {
  case 'INCREMENT':
    return state + 1;
  case 'DECREMENT':
    return state - 1;
  default:
    return state;
  }
}

// 创建 Redux store 来存放应用的状态。
// API 是 { subscribe, dispatch, getState }。
let store = createStore(counter);

// 可以手动订阅更新,也可以事件绑定到视图层。
const unsubscribe = store.subscribe(() =>
  console.log(store.getState())
)
// 改变内部 state 惟一方法是 dispatch 一个 action。 
//
action 可以被序列化,用日记记录和储存下来,后期还可以以回放的方式执行
store.dispatch({ type: 'INCREMENT' }); // 1
store.dispatch({ type: 'INCREMENT' }); // 2
store.dispatch({ type: 'DECREMENT' }); // 1
// 停止监听 state 更新
unsubscribe();

 

17、vue和react的异同

共同点:

(1)都使用虚拟dom。
(2)提供了响应式和组件化的视图组件。
(3)关注核心代码,将其他功能如路由和全局状态管理交给相关的库。(vue-router、vuex、react-router、redux等等)

区别:

(1)核心思想不同:

Vue定位是降低前端开发的门槛,更快地上手开发。特点:灵活易用的渐进式框架,进行数据拦截/代理,它对侦测数据的变化更敏感、更精确。

React定位是提出 UI 开发的新思路。推崇函数式编程(纯组件),数据不可变以及单向数据流,需要双向的地方可借助onChange和setState来实现。

(2)组件写法差异:

React推荐的做法是JSX + inline style, 把 HTML 和 CSS 全都写进 JavaScript 中,即 all in js;

Vue 推荐的做法是 template 的单文件组件格式,即 html,css,JS 写在同一个文件(vue也支持JSX写法)

(3)响应式原理不同

Vue:递归监听data的所有属性,直接修改。当数据改变时,自动找到引用组件重新渲染。

React:基于状态机,手动优化,数据不可变,需要setState驱动新的state替换老的state。当数据改变时,以组件为根目录,默认全部重新渲染。

(4)应用场景

Vue

1、构建数据简单中小型应用时:vue提供简单明了的书写模板、大量api、指令等等,可快速上手、开发项目
2、应用尽可能的小和快:随着vue3.0的发布,vue的体积进一步缩小,远小于react的体积,也配合diff算法,采用proxy去实现双向绑定,渲染大幅度提升

React

1、构建一个大型应用项目时:React的渲染系统可配置性更强
2、适用于Web端和原生APP:React Native是一个使用Javascript构建移动端原生应用程序(iOS,Android)的库。

 

18、快速删除node_modules

解决办法:

方法一:.进入项目所在目录使用CMD命令进入DOCS控制台执行如下命令即可快速删除。

rd /s /q node_modules
方法二:使用PowerShell或git bash进入命令控制台执行如下命令即可快速删除(推荐,速度比较快)。

rm -rf ./node_modules
方法三:直接在项目中使用npm的rimraf工具实现秒删(需要安装库)

npm install rimraf -g
rimraf node_modules

posted @ 2022-07-12 11:28  梁涛999  阅读(516)  评论(0编辑  收藏  举报