写在后面的话
依据React官网文档介绍,Hook是React 16.8的新增个性,它能够让你在不编写class的状况下应用state以及其余的React个性。
那么在有class组件的状况下,咱们为什么还要用Hook呢?在什么状况下应该用Hook组件呢?
React组件
React能够通过class和function两种形式创立组件。
class组件
class组件实例化要通过几个过程:
- 初始化组件
- 执行构造函数
- 继承父类属性
- 绑定事件
- 初始化state
这样做会带来肯定负作用:
- 大量组件实例化过程会占用内存,对性能造成肯定影响
- 如果在构造函数里通过bind绑定事件,代码可读性较差;而用箭头函数申明事件处理函数又容易造成子组件的反复渲染
函数组件
函数组件相当于申明了一个能够返回UI的函数,这样做的益处是没有了实例化过程,不会对内存造成累赘。相应的,因为没有实例化,函数组件也就没有本人的this,没有本身的state,更不能拜访生命周期钩子函数。函数组件又被成为无状态组件。
函数组件渲染须要的数据来自父组件传递的props
什么时候用函数式申明组件?
理论我的项目开发中的组件个别不会是简略的一层构造,通常是父组件嵌套几个子组件。咱们能够把须要用到生命周期解决逻辑、须要保护本身状态的父组件用class申明,简略的只须要接管父组件props的子组件用function申明。
React Hook
随着“函数式编程”思维的深刻,React开发了用于函数组件中挂钩状态和生命周期的Hook。有了Hook,组件中的状态不再是聚合成一个对象,而是离开独立治理;而且不再须要在开发时在意生命周期的应用,这给了开发者很大的自在。
Hook 是一个非凡的函数,它能够让你“钩入” React 的个性。例如,useState
是容许你在 React 函数组件中增加 state 的 Hook.
useState
上图中通过函数式申明了一个叫Counter的组件,并调用useState给组件申明了一个count的state。
调用useState时做了什么?
它定义一个 “state 变量”。这里的变量叫 count
, 然而咱们能够叫他任何名字,比方 banana
。这是一种在函数调用时保留变量的形式 —— useState
是一种新办法,它与 class 外面的 this.state
提供的性能完全相同。一般来说,在函数退出后变量就会”隐没”,而 state 中的变量会被 React 保留。
useState须要哪些参数?useState()
办法外面惟一的参数就是初始 state。不同于 class 的是,咱们能够依照须要应用数字或字符串对其进行赋值,而不肯定是对象。在示例中,只需应用数字来记录用户点击次数,所以传了 0
作为变量的初始 state。(如果咱们想要在 state 中存储两个不同的变量,只需调用 useState()
两次即可。)
useState返回什么?
返回值为:以后 state 以及更新 state 的函数。这就是咱们写 const [count, setCount] = useState()
的起因。这与 class 外面 this.state.count
和 this.setState
相似,惟一区别就是你须要成对的获取它们。
通过以上操作,咱们能够在UI中拿到count作为渲染数据,出现在视图上
useEffect
在下面的实例中,如果咱们想每点击一次按钮控制台就打印一次信息,应该怎么做呢
Effect Hook能够让你在函数组件中执行副作用操作。
useEffect做了什么?
通过应用这个 Hook,你能够通知 React 组件须要在渲染后执行某些操作。React 会保留你传递的函数(咱们将它称之为 “effect”),并且在执行 DOM 更新之后调用它。
为什么在组件外部调用useEffect?
将 useEffect
放在组件外部让咱们能够在 effect 中间接拜访 count
state 变量(或其余 props)。咱们不须要非凡的 API 来读取它 —— 它曾经保留在函数作用域中。Hook 应用了 JavaScript 的闭包机制,而不必在 JavaScript 曾经提供了解决方案的状况下,还引入特定的 React API。
useEffect会在每次渲染后执行吗?
是的,默认状况下,它在第一次渲染之后_和_每次更新之后都会执行。你可能会更容易接受 effect 产生在“渲染之后”这种概念,不必再去思考“挂载”还是“更新”。React 保障了每次运行 effect 的同时,DOM 都曾经更新结束。
能够说useEffect能够代替class组件中的componentDidMount、componentDidUpdate、componentWillUnmount生命周期,每次组件渲染完后组件都会执行useEffect的操作。
为什么useEffect能拿到每次更新的值?
组件每次渲染后都会生成新的effect,笼罩之前的值,这时拿到的count也是最新的
useEffect传递的参数
useEffect中传递的第一个参数是一个函数,示意组件渲染后要执行的操作。咱们还能够在组件中传第二个参数——这个参数示意useEffect执行的依赖,也就是说,只有这个参数发生变化时useEffect才会执行,这就实现了useEffect的优化
如果你要应用此优化形式,请确保数组中蕴含了所有内部作用域中会随工夫变动并且在 effect 中应用的变量,否则你的代码会援用到先前渲染中的旧变量。
如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),能够传递一个空数组([]
)作为第二个参数。这就通知 React 你的 effect 不依赖于 props 或 state 中的任何值,所以它永远都不须要反复执行。这并不属于非凡状况 —— 它仍然遵循依赖数组的工作形式。
React会在渲染实现后提早一段时间执行useEffect,这使得额定操作很不便。
useEffect返回值
每个effect都能够返回一个革除函数。如此能够将增加和移除订阅的逻辑放在一起。它们都属于effect的一部分。能够认为返回的函数会在组件卸载时执行,用来清理定时器等工作
React何时分明effect?
React 会在组件卸载的时候执行革除操作。正如之前学到的effect在每次渲染的时候都会执行。这就是为什么React会在执行以后 effect 之前对上一个 effect 进行革除。
为什么用Hook组件?
在组件之间复用状态逻辑很难
React 没有提供将可复用性行为“附加”到组件的路径(例如,把组件连贯到 store)。如果你应用过 React 一段时间,你兴许会相熟一些解决此类问题的计划,比方 render props 和 高阶组件。然而这类计划须要从新组织你的组件构造,这可能会很麻烦,使你的代码难以了解。如果你在 React DevTools 中察看过 React 利用,你会发现由 providers,consumers,高阶组件,render props 等其余形象层组成的组件会造成“嵌套天堂”。这阐明了一个更深层次的问题:React 须要为共享状态逻辑提供更好的原生路径。
你能够应用 Hook 从组件中提取状态逻辑,使得这些逻辑能够独自测试并复用。Hook 使你在无需批改组件构造的状况下复用状态逻辑。 这使得在组件间或社区内共享 Hook 变得更便捷。
简单组件变得难以了解
咱们常常保护一些组件,组件起初很简略,然而逐步会被状态逻辑和副作用充斥。每个生命周期经常蕴含一些不相干的逻辑。例如,组件经常在 componentDidMount
和 componentDidUpdate
中获取数据。然而,同一个 componentDidMount
中可能也蕴含很多其它的逻辑,如设置事件监听,而之后需在 componentWillUnmount
中革除。互相关联且须要对照批改的代码被进行了拆分,而齐全不相干的代码却在同一个办法中组合在一起。如此很容易产生 bug,并且导致逻辑不统一。
在少数状况下,不可能将组件拆分为更小的粒度,因为状态逻辑无处不在。这也给测试带来了肯定挑战。同时,这也是很多人将 React 与状态治理库联合应用的起因之一。然而,这往往会引入了很多抽象概念,须要你在不同的文件之间来回切换,使得复用变得更加艰难。
为了解决这个问题,Hook 将组件中互相关联的局部拆分成更小的函数(比方设置订阅或申请数据),而并非强制依照生命周期划分。你还能够应用 reducer 来治理组件的外部状态,使其更加可预测。
真正拥抱函数式编程
Hook 使你在非 class 的状况下能够应用更多的 React 个性。 从概念上讲,React 组件始终更像是函数。而 Hook 则拥抱了函数,同时也没有就义 React 的精力准则。Hook 提供了问题的解决方案,无需学习简单的函数式或响应式编程技术。