深入理解React Hooks

简介: 深入理解React Hooks

前言:


看了一晚上react源码,有些感悟,趁着还没忘,赶紧记录下来。

1.react的执行机制带来的两个问题


之前看react文档,说是在不要再以下两种情况下使用hooks:

1.1 只在 React 函数中调用 Hook

1.2 不要在循环、条件或嵌套函数中调用 Hook

第一条好理解,因为react hooks本来就是给函数组件用的,在普通函数中使用没有意义。

第二条就令人困扰了,为啥?

image.png

import React, { useState } from "react";
let isMounted = false;
function PersonalInfoComponent() {
  let name, age, career, setName;
  console.log("isMounted", isMounted);
  if (!isMounted) {
    [name, setName] = useState("接着奏乐接着舞。");
    [age] = useState(18);
    isMounted = true;
  }
  [career] = useState("前端开发");
  console.log("career", career);
  return (
    <div className="personalInfo">
      <p>姓名:{name}</p>
      <p>年龄:{age}</p>
      <p>职业:{career}</p>
      <button
        onClick={() => {
          setName("接着奏乐接着舞2。");
        }}
      >
        修改姓名
      </button>
    </div>
  );
}
export default PersonalInfoComponent;

1.3 刨析:

通过源码得知:Hooks在首次渲染和更新渲染(除了首次渲染之外的)时分别执行了不同的逻辑,他的执行是一个链式的表(A==》B==》C),即:首次渲染时构建这个链表,其他时候都是根据这个链表依次遍历,是有顺序的,就和数组遍历差不多的道理,那么上面的情况就明朗了,上面用了判断有时候3个hook成立有时候1个hook成立,那就很可能出错。

1.4 小结:为什么不要在循环、条件或嵌套函数中调用 Hook?

答案是:hooks的首次渲染和更新渲染执行的是不同的逻辑,第一次渲染时会构建链表,后续的渲染会根据这个链表依次遍历渲染。

因此在循环(会多会少)、条件(会多会少)、嵌套函数(有时执行有时不执行)中均不可使用(导致不可预测的问题)

1.4 相应的源码:

-----定义useState  开始------------
export function useState(initialState) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useState(initialState);
}
-----定义useState  结束------------
当函数组件进入 render 阶段 的时候,
如果发现组件内存在 Hooks ,
那么会调用 renderWithHooks (opens new window)方法,
在这个方法中会根据不同渲染情况对当前的 dispatcher 进行赋值
ReactCurrentDispatcher.current =
  current === null || current.memoizedState === null ?
  HooksDispatcherOnMount :
  HooksDispatcherOnUpdate;
--------最终的结果--------
通过上面的代码可以看到:
第一次渲染执行的是 :HooksDispatcherOnMount函数
后面的渲染执行的是:HooksDispatcherOnUpdate函数

2.setState到底是同步还是异步?


先说结论:时而同步时而异步,结合原理具体说说?

通过研究源码可以得出:setState的执行是批量更新+开关锁

意思就是,react不会你改一次它渲染一次,而是攒着,等你改完了,我只需要修改一次就好了,我写一个伪代码包含开关锁的使用哈:

image.png

看我图上的标注后是否恍然大悟,那么上图会打印1 1这个结果也是可以接受了。

这就会使得setState是异步。

2.1 setState小结:

setState 并不是单纯同步或异步的,它的表现会因调用场景的不同而不同:

在 React 钩子函数及合成事件中,它表现为异步;

而在 setTimeout 、 setInterval 等函数中,包括在 DOM 原生事件中,它都表现为同步(原因是,这个锁是同步执行,而异步肯定比同步晚,等执行settimeout里面的时候锁已经开了)

这种差异,本质上是由 React 事务机制和批量更新机制的工作方式来决定的。

3. 逻辑复用:高阶组件(HOC)、render props、hooks


3.1 举例场景:

我要判断用户是否登录来展示不同的内容,且这个功能我要在跟多个地方使用。

3.2 高阶组件的方式:

下面的代码例子就是使用高阶组件封装的,我们只需在要用的时候,传入组件即可

import checkUserAccess from './utils
const withCheckAccess = (WrappedComponent) => {
    //checkUserAccess()方法返回一个布尔值来确定是否登录,是咱们封装的逻辑 
    const isAccessible = checkUserAccess()  
    // 将 isAccessible(是否登录) 这个信息传递给目标组件
    const targetComponent = (props) => (
        <div className="wrapper-container">
            <WrappedComponent {...props} isAccessible={isAccessible} />
        </div>
    );
    return targetComponent;
};
----------使用-----------
const EnhancedAComponent = withCheckAccess(Acomponent);

3.3 高阶组件小结:

高阶组件说白了,就是一个函数接收一个组件,经过函数处理返回一个加强过的组件。

3.4 Render props方式:

import checkUserAccess from './utils
// 定义 render props 组件
const CheckAccess = (props) => {
  const isAccessible = checkUserAccess()
  // 将 isAccessible(是否登录) 这个信息传递给目标组件
  return <React.Fragment > {
      props.children({
        ...props,
        isAccessible
      })
    } <
    /React.Fragment>
};
-------使用如下---------
<CheckAccess>
  {
    (props) => {
      const { isAccessible } = props;
      return <ChildComponent {...props} isAccessible={isAccessible} />
    }
  }
</CheckAccess>

3.5 Render props方式小结:

Render props说白了,就是应该是一个React 组件,并且它的子组件需要以函数形式存在。。

相关文章
|
14天前
|
前端开发 JavaScript
深入理解并实践React Hooks —— useEffect与useState
深入理解并实践React Hooks —— useEffect与useState
66 1
|
3天前
|
前端开发 JavaScript
React_函数式Hooks和Class比较优缺点
React Hooks与Class组件都能返回JSX并接收props,但Hooks无`this`指向问题,用`useEffect`模拟生命周期,`memo`优化性能,状态更新用`useState`;Class组件通过生命周期方法、`PureComponent`或`shouldComponentUpdate`优化,状态用`this.state`和`this.setState`管理。
13 1
React_函数式Hooks和Class比较优缺点
|
3天前
|
前端开发 JavaScript
React中函数式Hooks之useRef的使用
React中函数式Hooks的useRef用于获取DOM元素的引用,示例代码演示了其基本用法。
16 3
|
3天前
|
前端开发
React中函数式Hooks之useEffect的使用
本文通过示例代码讲解了React中`useEffect` Hook的用法,包括模拟生命周期、监听状态和清理资源。
13 2
React中函数式Hooks之useEffect的使用
|
2天前
|
前端开发 JavaScript API
深入探索React Hooks与状态管理
深入探索React Hooks与状态管理
11 2
|
10天前
|
前端开发 JavaScript 开发者
深入探索React Hooks的魔力
深入探索React Hooks的魔力
37 10
|
3天前
|
缓存 前端开发
React中函数式Hooks之memo、useCallback的使用以及useMemo、useCallback的区别
React中的`memo`是高阶组件,类似于类组件的`PureComponent`,用于避免不必要的渲染。`useCallback` Hook 用于缓存函数,避免在每次渲染时都创建新的函数实例。`memo`可以接收一个比较函数作为第二个参数,以确定是否需要重新渲染组件。`useMemo`用于缓存计算结果,避免重复计算。两者都可以用来优化性能,但适用场景不同:`memo`用于组件,`useMemo`和`useCallback`用于值和函数的缓存。
14 1
|
3天前
|
前端开发
React中函数式Hooks之useState的使用
本文介绍了React中函数式组件的Hooks——`useState`的使用方法。`useState`允许在函数式组件中使用状态,它返回一个数组,其中包含当前状态的值和更新该状态的函数。文章通过示例代码展示了如何声明状态变量和更新状态变量,包括对数值和对象状态的更新。此外,还展示了如何通过点击按钮触发状态更新,实现交互功能。
11 1
|
3天前
|
前端开发
React使用hooks遇到的坑_state中的某几个属性数据变成了空字符
本文讨论了在React使用hooks时遇到的一个问题:state中的某些属性数据变成了空字符。作者通过在修改函数中重新解构赋值来获取最新的state值,解决了因数据更新不及时导致的问题。
11 0
|
3天前
|
缓存 前端开发
React中函数式Hooks之useMemo的使用
React的`useMemo` Hook 用于优化性能,通过记忆返回值避免重复计算。它接收一个函数和一个依赖数组,只有当依赖项改变时,才会重新计算被记忆的值。这可以用于避免在每次渲染时都进行昂贵的计算,或者防止子组件不必要的重新渲染。例如,可以在父组件中使用`useMemo`包裹子组件,以依赖特定的props,从而控制子组件的渲染。
11 0

热门文章

最新文章