React Component Review
class component
在React的Class组件,主要由四个部分组成。
第一部分是constructor(props){},在这里声明这个类拥有的全部状态。这一部分属于data/state类别。
第二部分是组件内部用于修改状态的函数,一般都被赋予一个变量,在其他地方被调用。
第三部分是生命周期函数,用于控制该组件在渲染过程的不同阶段会执行什么样的动作,也是一个函数。这一部分属于actions类别。
第四部分也就是render(){}部分,return部分使用JSX表达式,告诉浏览器要如何渲染上面定义的组件。这一部分属于view/UI类别。
function component
函数组件更像是只关心class组件的第四部分,也就是UI部分。不考虑数据与数据的变化。本质上就是DOM createElement的语法糖。
我们在构建网页的时候,一开始只考虑UI,也就是把静态网页先搭建出来,这个时候我们只需要使用函数组件。但是随着功能的复杂化,一开始的函数组件可能需要开始拥有自己的状态与数据了,这个时候需要把函数组件包装到class组件中去,或者重构代码将函数组件重写成class组件;而class组件可能又要被包裹到更高级别的组件中去,这样子层层嵌套十分麻烦。虽然引入了单项数据流的概念,管理与检查错误还是十分麻烦。
因此出现了用于增强函数组件的HOOKs。通过hooks在函数组件内部实现state和action,可能在函数组件之间实现共享state和action。这样一来,功能性上函数组件与HOOKs等同于class组件。
Hooks
Hooks are functions that let you “hook into” React state and lifecycle features from function components.
useState
useState
is a Hook that lets you add React state to function components.
有了useState Hook之后,在一个函数组件被创建且你发现它需要添加状态时,就不需要再把它转换为class组件了。相当于替代了class组件中的第一部分constructor以及第二部分修改状态的函数。
使用方法如下:
1 | import React, { useState } from 'react'; |
单看等号右边的useState()就相当于声明了一个状态变量,他接受一个初始状态值作为参数。
看等号左边的一个数组,有两个值,第一个是当前状态,第二个是用于更新状态的函数。类比一下class组件,这就相当于this.sate.current_state1和this.setState{current_state1: }这两个语句。
右边赋值给左边用到了array destructing语法,把useState的第一个返回值当前状态赋值给array索引为0的count,把用于更新状态的函数赋值给array索引为1的setCount。
useEffect
By using useEffect Hook, you tell React that your component needs to do something after render.
有了useEffect Hook以后,在一个函数组件被创建且每一次的DOM渲染都有可能要执行一些其他动作的时候,就不需要把它转换为class组件并且在class组件内部多次调用生命周期函数了。相当于替代了class组件中第三部分生命周期函数。
需要注意的是不同的业务逻辑的副作用可以用不同的useEffectHook来表现,而在生命周期函数中无论什么业务逻辑都按照生命周期的流程在区分。我们希望split the code based on what it is doing rather than a lifecycle method name.。
使用方法如下:
useEffect函数会在每一次render渲染更新的时候运行。不像生命周期函数分为多个mounting和updating之类的多个阶段,他只是run after render。
1 | useEffect(() => { |
effects with cleanup
如果在每次渲染并且施加effect之后还需要cleanup this effect,可以在useEffect函数中添加一个return语句,指明需要cleanup。类比到class组件就是ComponentDidMount与ComponentWillUnmount这两个生命周期。
在每一次apply the effect之后都会在有一个cleanup this effect;否则不会在调用另一个apply the effect。(?存疑)
useEffect on Condition
但是每一次重新渲染都cleaning up or applying the effect会导致性能问题,tell React to skip applying an effect if certain values haven’t changed between re-renders,因此给useEffect函数传入第二个参数,这个参数的形式是由函数内部变量组成的数组,告诉react只在这个内部变量变化时进行effect。在class组件中,通常是在ComponentDidUpdate中进行值的比较,如state或者props。
multiple effects to Separate Concerns
由于useEffect在函数组件内部被调用,这样useEffect函数就可以访问到函数组件内部的状态,也就是说每一次的after render effect都是不同的state变化引起的不同的effect。
Rules of Hooks
Don’ t call Hooks inside loops, conditions, or nested functions. Only Call Hooks at the Top Level.不要在循环、条件、嵌套中使用。
因为每一个hook都有他相关的数据管理域,react通过识别hook的调用顺序来匹配相关数据管理区域。如果有条件或者嵌套,这种顺序就会被打乱。
As long as the order of the Hook calls is the same between renders, React can associate some local state with each of them.
Don’ t call Hooks from regular JavaScript functions.只在函数组件、自定义hook中调用hook。
自定义hook的明明遵循useHook的书写规范。
Redux
Redux是基于React的一个数据/状态管理库。
Redux is a pattern and library for managing and updating application state, using events called “actions”.
状态/数据管理面临的挑战
在React的组件中,有两种组件模式。第一种是传统的class组件,通过组件嵌套,state到props的抽象完成数据管理。第二种是函数组件,通过HOOKs API的useState()与useEffect()实现和传统class组件相同的功能。
他们都被称作self-contained app。主要由三个部分组成:
- The state, the source of truth that drives our app;
- The view, a declarative description of the UI based on the current state
- The actions, the events that occur in the app based on user input, and trigger updates in the state
当我们需要在组件之间共享状态/数据时该怎么做?React核心概念中提出了lifting state up to parent components状态提升至父组件。那这又涉及到抽象与嵌套,state到props的转变,不停地在变换多种组件构成的树component tree,十分麻烦。
一个方法就是把这些所有需要共享的数据/状态抽取出来集中管理,与component tree割裂开来。这也就是Redux的核心思想——This is the basic idea behind Redux: a single centralized place to contain the global state in your application, and specific patterns to follow when updating that state to make the code predictable.
- 本文标题:React数据管理之Hooks与Redux
- 本文作者:徐徐
- 创建时间:2020-12-04 10:36:54
- 本文链接:https://machacroissant.github.io/2020/12/04/redux-hooks/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!