You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
exportfunctionReactEcharts(props){const{option, loading}=propsconstcontainer=useRef(null)constchart=useRef(null)useEffect(()=>{constwidth=document.documentElement.clientWidthconstc=container.currentconsole.log(c)c.style.width=`${width-20}px`c.style.height=`${(width-20)*1.2}px`chart.current=echarts.init(c,'dark')},[])// [] - mounted on first timeuseEffect(()=>{chart.current.setOption(option)},[option])// when option change 类似 vue 的 watchuseEffect(()=>{if(loading)chart.current.showLoading()elsechart.current.hideLoading()},[loading])return(<divref={container}/>)}
依赖项过多问题
a. 去掉不必要的依赖
b. 将 Hook 拆分为更小的单元,每个 Hook 依赖于各自的依赖数组
c. 合并相关的 state,将多个依赖值聚合为一个
d. 通过 setState 回调函数获取最新的 state,以减少外部依赖
e. 通过 ref 来读取可变变量的值,不过需要注意控制修改它的途径
useEffect 和生命周期函数不做类比,useEffect 单纯用作处理副作用
A "side effect" is anything that affects something outside the scope of the function being executed. These can be, say, a network request, which has your code communicating with a third party (and thus making the request, causing logs to be recorded, caches to be saved or updated, all sorts of effects that are outside the function.
上次的一次搞定前端四大手写在知乎上收获了500多个赞,简直让我受宠若惊。今天就趁热打铁,写一下一次搞定七大 React Hooks,一方面是为了复习下 React,另一方面是跟小伙伴们分享一些我学习 React Hooks 时的心得体会。由于水平有限,目前只能从 React Hooks 的基本使用方法和使用要点上做些分享,关于 Hooks 的原理上的探究日后再做更新。
让我们先来看道字节面试题,题目是实现一个自定义的 Hook,实现点击切换状态。
七大 Hooks 都有哪些
useState
状态useEffect
钩子,还有它的兄弟useLayoutEffect
useContext
上下文useReducer
代替 ReduxuseMemo
缓存,还有它的小弟useCallback
useRef
引用自定义 Hook
混合useState
基本语法:
const [X, setX] = React.useState(X的初始值)
简单示例:
我们会发现,点击按钮之后,age 消失了,而我们明明只改了 name 呀,为什么呢?
简单来说就是前后是两个完全不相关的对象。
展开讲的话 React 在数据变化时会创建新的虚拟 DOM 对象,然后将这个虚拟 DOM 对象跟原虚拟 DOM 进行一个 DOM Diff,得到一个最小的变化过程 Patch,并把这个 Patch 渲染到页面上,Diff 的时候发现新对象没有 age 这个属性,于是就把它删除了。
于是在使用 useState 的时候我们需要注意两个地方:
setUser({...user, name: 'Janye'})
useEffect
useEffect
的作用主要是用来解决函数组件如何像类组件一样使用生命周期钩子的问题。它有三个使用场景:
[]
这里给一个最简单的例子:
那么它跟它的兄弟
useLayoutEffect
有什么区别呢?useEffect
在浏览器渲染完成后执行,useLayoutEffect
在浏览器渲染前执行,useLayoutEffect
总是比useEffect
先执行。那么为了用户体验(先渲染就能先看到),通常我们应该先用
useEffect
。useContext
如果我们想在组件之间共享状态的话,可以使用
useContext
。它的使用可以分为三个步骤:
C = createContext(initial)
创建上下文<C.provider>
圈定作用域useContext(C)
来使用上下文简单示例:
useReducer
如果要一句话解释
useReducer
的话,它是用来代替 Redux 的,或者说,是一个加强版的useState
。使用上来说,一共有四步:
写({type: '操作类型'})
这里给一个基本的示例:
useMemo
基本语法:
useMemo(回调函数, [依赖])
类似与 Vue 的计算属性 computed,useMemo 具有缓存,依赖改变才重新渲染的功能。
跟它的小弟
useCallback
的唯一区别是:useMemo
可以缓存所有对象,useCallback
只能缓存函数。useCallback(x => log(x), [m])
等价于useMemo(() => x => log(x), [m])
useRef
主要作用是创建一个数据的引用,并让这个数据在 render 过程中始终保持不变。
基本语法:
const count = useRef(0)
,读取用count.current
用法这里给大家参考一下我封装 Echarts 时的例子:
自定义 Hook
可以理解为我们可以把上面的 Hook 按照实际的需求混合起来,封装成一个函数,给一个简单示例:
Hooks 的一些最佳实践分享
useState
useEffect
a. 去掉不必要的依赖
b. 将 Hook 拆分为更小的单元,每个 Hook 依赖于各自的依赖数组
c. 合并相关的 state,将多个依赖值聚合为一个
d. 通过 setState 回调函数获取最新的 state,以减少外部依赖
e. 通过 ref 来读取可变变量的值,不过需要注意控制修改它的途径
a. 每次副作用执行,都会返回一个新的clear函数
b. clear函数会在下一次副作用逻辑之前执行(DOM渲染完成之后)
c. 组件销毁也会执行一次
useCallback
可以优化为:
useMemo
a. 保持引用相等
b. 成本很高的计算
a. 返回的值是原始值:string, boolean, null, undefined, number, symbol
b. 对于一些简单的 JS 运算(数组操作)来说,我们不需要使用 useMemo
c. 仅在组件内部用到的 object、array、函数等(没有作为 props 传递给子组件),且没有用到其他 Hook 的依赖数组中,一般不需要使用 useMemo。
错误示例:
在 useCount Hook 中, count 状态的改变会让 useMemo 中的 increase 和 decrease 函数被重新创建。由于闭包特性,如果这两个函数被其他 Hook 用到了,我们应该将这两个函数也添加到相应 Hook 的依赖数组中,否则就会产生 bug。比如:
在 useCount 中,increase 会随着 count 的变化而被重新创建。但是 increase 被重新创建之后, useEffect 并不会再次执行,所以 useEffect 中取到的 increase 永远都是首次创建时的 increase 。而首次创建时 count 的值为 0,因此无论点击多少次, count 的值永远都是 1。
解决方案:
1)通过 setState 回调,让函数不依赖外部变量
2)通过 ref 来保存可变变量
自定义 Hook
推荐阅读
useEffect 完整指南
五个大型项目实战总结,解密React Hooks最佳实践方式
React Hooks 你真的用对了吗?
useEffect使用指南
使用 React Hooks 声明 setInterval
写在最后
过去一年的一些感悟跟大家分享一下:
The text was updated successfully, but these errors were encountered: