# react hook 基础问题
react hook引入是为了解决状态共享的问题
- 状态逻辑复用,并将 UI 于状态分离,function state 保存的是快照,class state保存的是值,引用类型的情况下,class state 不需要传入新的引用,而 function state 必须保证是个新的引用?
- 快照(闭包) vs 最新值(引用)?快照每次更新都是重新执行当前函数,每次都是重新获取初始值再更新----用useRef 来解决,在渲染周期内永远不会变,因此可以用来引用某些数据,修改 ref.current 不会引发组件重新渲染。
- 异步更新机制 与 事件
useRef vs createRef:
- 两者都是获取 ref 的方式,都有一个 current 属性。
- useRef 只能用于函数组件,createRef 可以用在类组件中。
- useRef 在每次重新渲染后都保持不变,而 createRef 每次都会发生变化。
生命周期
- 可以一定程度上用 useEffect 充当,componentDidMount、componentDidUpdate、componentWillUnmount
- 执行时机----如果不传依赖数组,那么回调函数会在每一次渲染结束后(componentDidMount 和 componentDidUpdate)执行。如果依赖数组不为空数组,那么回调函数会在依赖值每次更新渲染结束后(componentDidUpdate)执行,这个依赖值一般是 state 或者 props。
- useLayoutEffect:useLayoutEffect 会block 浏览器渲染,是在 DOM 更新完成后,浏览器绘制之前执行。
箭头函数有个问题,那就是在每一次组件重新渲染的时候都会生成一个重复的匿名箭头函数,导致传给组件的参数发生了变化,对性能造成一定的损耗。
并发渲染,react 大量计算与渲染阻塞了主线程,用另一个线程来完成?webworker?
- useDeferredValue---在整个渲染过程中确定工作的优先级,标记哪些具体的状态拥有更低的优先级
- startTransition 可以明确的告诉 React 哪些更新具有更低的优先级
是一个 React 组件,fallback
- 为什么是函数式组件?
- 简化了逻辑的复用<----->高阶组件,需要用到复杂的设计模式,(为了传递一个公共的外部状态,定义一个没有 UI 的外层组件)
- 有助于关注分离:把相关的业务逻辑代码尽可能的聚合在一起,类组件都是分散在各个生命周期里面
- React 组件的实质?
- React 组件的模式其实是 Model 到 View 的映射,也就是 state 和 props到 View 的映射,用到数据绑定
- 可以把 UI 的展现看成是一个函数执行的过程,Model 是输入参数,执行结果是 DOM 树,就是每当 Model 发生变化时,函数会重新执行,并且生成新的 DOM 树,然后 React 再把新的 DOM 树以最优的方式更新到浏览器。
- 函数和对象不同,并没有一个实例的对象能够在多次执行之间保存状态,所有就需要一个函数之外的空间来保存这个状态,而且要能够检测其变化,从而能够触发函数组件的重新渲染。
- 所以我们需要能够把一个外部的数据绑定到函数的执行。当数据变化时,函数能够自动重新执行。这样的话,
只要是会影响 UI 展现的外部数据,都可以通过这个机制绑定到 React 的函数组件。 - Hooks 就是把某个目标结果钩到某个可能会变化的数据源或者事件源上,那么当被钩到的数据或事件发生变化时,产生这个目标结果的代码会重新执行,产生更新后的结果。
- 对于 useCallback、useMemo 这样与缓存相关的组件,则是在依赖项发生变化时去更新缓存。
- Class类不适合的原因
- 占用大量的内存
- 组件直接不互相继承,没有利用其继承性
- UI 是状态驱动的,很少会在外部调用一个类实例,组件的所有方法都是内部调用的,或者作为生命周期的方式被调用的
- 之前的函数组件无法提供内部状态,即生命周期
- useState 是什么?
- 让函数组件具有维持状态的能力,在多次函数组件渲染之间,这个 state 是共享的,其返回值是长度为 2 的数组,第一个为读取的,第二个是更新函数,可以定义多个 state;而类组件中的 state 只能有一个
- state 中永远不要保存可以通过计算得到的值?
- 从
props传递过来的值。有时候 props 传递过来的值无法直接使用,而是要通过一定的计算后再在 UI 上展示,比如说排序。那么我们要做的就是每次用的时候,都重新排序一下,或者利用某些 cache 机制,而不是将结果直接放到 state 里。 - 从
URL中读到的值。比如有时需要读取 URL 中的参数,把它作为组件的一部分状态。那么我们可以在每次需要用的时候从 URL 中读取,而不是读出来直接放到 state 里。 - 从
cookie、localStorage中读取的值。通常来说,也是每次要用的时候直接去读取,而不是读出来后放到 state 里。+ 一旦组件有自己状态,意味着组件如果重新创建,就需要有恢复状态的过程,这通常会让组件变得更复杂。????-----redux
- 从
- useEffect 执行一段副作用----执行不影响渲染出来的 UI的代码
- 执行时机:每次函数组件 render执行完成之后判断依赖后执行,或组件销毁之前执行
- useEffect 还允许你返回一个函数,用于在组件销毁的时候做一些清理的操作。
- 依赖项注意点:再回调函数中用到的;是一个常量数组;依赖项是浅比较,
而数组或者对象是每次都创建一个新对象???(函数内部创建的) - 只能在函数组件的顶级作用域使用;只能在函数组件或者其他 Hooks 中使用。
- Hooks 在组件的多次渲染之间,必须按顺序被执行。React 组件内部,其实是维护了一个对应组件的固定 Hooks 执行列表的,以便在多次渲染之间保持 Hooks 的状态
- useCallback:缓存回调函数---事件回调,数据计算过程
- 执行时机:每次函数组件 render执行完成之后判断依赖后执行,组件销毁之前
- 但是因为定义是在函数组件内部,因此在多次渲染之间,是无法重用 函数组件内部 这个函数的,而是每次都需要创建一个新的
- 需要每次依赖变化时,才重新定义一个新的回调函数
- useMemo: 避免重复计算,避免子组件的重复渲染
- useRef: 多次渲染之间共享数据
- 使用 useRef 保存的数据一般是和 UI 的渲染无关的,还可以保存某个 DOM 节点的引用
- useContext: 定义全局状态----跨层次数据传递,从某个组件为根组件的组件树上可用, 这个组件树上的组件都可以修改和访问这个 context
- 创建 ThemeContext, 使用
<ThemeContext.Provider value={}><comp></ThemeContext.Provider>
<!-- 获取useContext(ThemeContext) -->
1
2
2
设计复杂的原因:为了能够进行数据的绑定
缺点:
- 会让调试变得困难,因为你很难跟踪某个 Context 的变化究竟是如何产生的。
- 让组件的复用变得困难,因为一个组件如果使用了某个 Context,它就必须确保被用到的地方一定有这个 Context 的 Provider 在其父组件的路径上。
- Context 更多的是提供了一个强大的机制,让 React 应用具备定义全局的响应式数据的能力。比如 Redux,正是利用了 Context 的机制来提供一种更加可控的组件之间的状态管理机制。因此,理解 Context 的机制,也可以让我们更好地去理解 Redux 这样的框架实现的原理。
转换思路:实现的是一次性的代码执行
自定义 Hooks----use开头,函数中有用到其它 Hooks
Redux:
- 跨组件的状态共享,如全局组件 Loading;
- 同组件多个实例的状态共享:某个页面组件初次加载时,会发送请求拿回了一个数据,切换到另外一个页面后又返回。这时数据已经存在,无需重新加载。设想如果是本地的组件 state,那么组件销毁后重新创建,state 也会被重置,就还需要重新获取数据。
- 主要就是三个:State、Action 和 Reducer。
- 其中 State 即 Store,一般就是一个纯 JavaScript Object。
- Action 也是一个 Object,用于描述发生的动作。
- 而 Reducer 则是一个函数,接收 Action 和 State 并作为参数,通过计算得到新的 Store。
# react-hooks 原理
- react 用什么方式记录了 hooks 的状态
- 多个react-hooks用什么来记录每一个hooks的顺序的 ?
- 函数组件中的useState,和 class类组件 setState有什么区别?
- react 是怎么捕获到hooks的执行上下文,是在函数组件内部的?
- useEffect,useMemo 中,为什么useRef不需要依赖注入,就能访问到最新的改变值?
- useMemo是怎么对值做缓存的?如何应用它优化性能?
- 为什么两次传入useState的值相同,函数组件不更新?
每一次函数上下文执行,所有变量,常量都重新声明,执行完毕,再被垃圾机制回收。
组件销毁,组件更新?
预渲染