
React Hook 对于React来说无疑是一个伟大的特性,它将React从类组件推向了函数组件,从而让人们对于JavaScript的理解不再去可以理解晦涩的JS中的类,以及难以琢磨的this。在《你不知道的JavaScript》上卷中,作者就对JavaScript中的类,继承,面向对象做了一定的解释,总的来说就是,在JavaScript中生搬硬套用面向对象,得不偿失,很容易造成学习和理解负担。
在React16之前没有Hook的时候,必须在类组件去维护组件状态,因此必须理解JS中this的工作机制,并且在给元素绑定事件的时候总是需要绑定this。在组件之间复用状态逻辑比较困难,官方提供的 render props 和 高阶组件 确实很好用,但是整个用起来感觉很重,具体关于对类组件的吐槽可以参考React官网 Hook简介 这部分内容。
当使用React Hook去写React应用后,会发现再也不想用类组件了。。。
官方是这么介绍Hook的: Hook 是 React 168 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
在React中提供了以下几种Hook
示例:
将useState这个钩子从react中导入,在函数组件Login中利用解构赋值的方式声明两个常量 num , setNum 作为 useState(0) 的返回值,useState钩子返回一个数组,第一个参数是我们声明的 state变量 ,第二个参数是一个 方法 ,用来手动改变第一个参数。
语法: const [num, setNum] = useState(0)
useState接受参数为基本类型如数字字符串等,也可以是引用类型对象数组等。用来作为初始值。
关于 useState返回值的第二个参数
示例:
官网这么说:如果你熟悉 React class 的生命周期函数,你可以把 useEffect Hook 看做 componentDidMount , componentDidUpdate 和 componentWillUnmount 这三个函数的组合。
useEffect接收一个 函数 为第一个参数。
关于useEffect 这个Hook,它的形式有以下几种:
说了这么多那到底什么是 副作用 ?
React官网是这样解释的:数据获取,设置订阅以及手动更改 React 组件中的 DOM 都属于副作用。不管你知不知道这些 *** 作,或是“副作用”这个名字,应该都在组件中使用过它们。
也就是说,当函数在运行的过程中对外部环境造成影响,或者与外部环境发生交互。比如 *** 作DOM,发起请求,设置订阅这种,都属于副作用。同时有些副作用需要清除,比如订阅解绑,定时器延时器清除,有些不需要清除,比如数据获取, *** 作DOM。
那什么样的函数没有副作用呢?纯函数是不会有副作用的。
在使用useEffect hook的时候可以使用多个Effect分离关注点:
举一个场景来说下:d窗场景。在父组件中点击按钮打开d窗,在d窗内部点击关闭按钮关闭d窗。
此时控制d窗打开与关闭的只能是一个状态isOpen,此时这个isOpen状态就需要在字符组件中共享。
使用isOpen控制d窗的显示与隐藏,在父组件中调用setIsOpen方法,打开d窗,在d窗组件中使用useContext共享的父组件中的方法setIsOpen关闭d窗。
注:父子组件一般不会存在一个文件中,需要将popContext导出再在子组件中导入使用。
官网这样解释: useState 的替代方案。它接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法。(如果你熟悉 Redux 的话,就已经知道它如何工作了。)
示例:
useReducer第一个参数是一个reducer函数,第二个参数是初始化状态,在reducer函数中根据不同的type对state进行不同的处理。类似于redux中的reducer。
useRef 返回一个可变的 ref 对象,其 current 属性被初始化为传入的参数( initialValue )。返回的 ref 对象在组件的整个生命周期内保持不变。
这个看来有两种用法:
第一种就是命令式 *** 作DOM元素
第二种是关于其另外一个特性变更 current 属性不会引发组件重新渲染
使用 myRefcount 来统计组件渲染次数。每一次组件重新渲染的时候,都将返回同一个 myRef 对象,并且, myRef 对象发生变化时,并不会导致组件渲染,这样的特性可以用来处理一些特殊场景下的需求。
当自定义一个myRef对象时,每次组件重新渲染都将返回一个新的对象。
这两个Hook可以用来做优化,比如以下例子,有name和age两个状态,子组件只需要在name发生变化时重新渲染,而在age发生变化时不需要重新渲染。
示例:
useMemo第一个参数接收一个函数第二个参数接收一个数组 useMemo(()=>fn, []) ,数组里面是依赖,只有数组里面的依赖发生变化,函数才会执行。
useCallback(fn, deps) 相当于 useMemo(() => fn, deps) 。
React 官方也在极力推动Hook的发展,并且近期也有了React准备重写文档,更新后的文档针对Hook的内容肯定会更多,而且Vue在30版本出来后也使用了类似于React Hook的机制Composition API,这也是一个趋势。
最近在用webpack4+react16+ts4做自己的一个移动端小博客,功能正在完善中,主要是想学习使用一下React技术栈,期间发现React Hook确实非常好用,因此做一些记录。
博客 github 地址: >
接收一个(state, action)=>newState的reducer,返回当前state及配套dispatch
优势:
1、处理复杂逻辑的state及state间有依赖的
2、给那些触发深更新的组件做新能优化;因为 你可以向子组件传递 dispatch 而不是回调函数 ;也就是如何避免向下传递回调?
在大型的组件树中,我们推荐的替代方案是通过 context 用 useReducer 往下传一个 dispatch 函数
React 会确保 dispatch 函数的标识是稳定的,并且不会在组件重新渲染时改变;
初始化useReducer的state:
1、将初始 state 作为第二个参数传入 useReducer 是最简单的方法;React 不使用 state = initialState 这一由 Redux 推广开来的参数约定。
2、 惰性初始化 :需要将 init 函数作为 useReducer 的第三个参数传入,这样初始 state 将被设置为 init(initialArg);这么做可以将用于计算 state 的逻辑提取到 reducer 外部,这也为将来对重置 state 的 action 做处理提供了便利
跳过dispatch
如果 Reducer Hook 的返回值与当前 state 相同,React 将跳过子组件的渲染及副作用的执行。(React 使用 Objectis 比较算法 来比较 state。)
需要注意的是,React 可能仍需要在跳过渲染前再次渲染该组件。不过由于 React 不会对组件树的“深层”节点进行不必要的渲染,所以大可不必担心。如果你在渲染期间执行了高开销的计算,则可以使用 useMemo 来进行优化。
===============================================
解决的问题:
可以在函数组件中添加state而不必转换成class组件
该使用单个还是多个state变量?
1、如果使用单个state变量,需要手动合并
function handleWindowMouseMove(e) {
// 展开 「state」 以确保我们没有 「丢失」 width 和 height
setState(prevState => ({ prevState, left: epageX, top: epageY }));
}
2、或者可以拆分成多个state变量
const [position, setPosition] = useState({ left: 0, top: 0 });
const [size, setSize] = useState({ width: 100, height: 100 });
useState特点:
1、调用 useState 方法的时候做了什么 它定义一个 “state 变量”,和class里的state功能相同,函数退出后state会被React保留,而不会消失;
2、useState的参数就是初始state,class中的state是个对象,而useState中的state可以是数字、字符串、对象;
3、sueState的返回值为当前state以及更新state的函数,与class 的区别是要成对的获取
4、class中的thisstate是合并,而hooks中的state是替换
为什么叫useState而不是createState
1、create可能不准确,因为state只在组件首次渲染的时候被创建,在下次重新渲染时,useState返回给我们当前的state。这个也是hook的名字总是以use开头的原因;
2、我们将在后面的 Hook 规则 中了解原因。
3、你可能会好奇 React 怎么知道 useState 对应的是哪个组件,因为我们并没有传递 this 给 React。我们将在 FAQ 部分回答 这个问题 以及许多其他问题
React 保持对当先渲染中的组件的追踪。多亏了 Hook 规范 ,
每个组件内部都有一个「记忆单元格」列表。它们只不过是用来存储一些数据的 JavaScript 对象。当你用 useState() 调用一个 Hook 的时候,它会读取当前的单元格(或在首次渲染时将其初始化),然后把指针移动到下一个。这就是多个 useState() 调用会得到各自独立的本地 state 的原因
==============
区别:如果修改规则比较复杂,那么将复杂规则放在reducer中使用useReducer比较合适,如果使用的规则比较简单,则可以使用useState的更新state函数中
react的hooks相当于在函数组件中注入了一些能力使其拥有和之前class一样的能力甚至更high
stateHook
引入statehook
定义state和处理函数
读取state
更新state
useEffect(在渲染或销毁后更新回调,多次定义依次调用)
引入useEffect
根据写法,react将自动帮我们识别回调时机
当某个或多个值在渲染后不希望其更新,则只指定需要react监听的值去跳过其他值的变化回调
useContext
引入useContext
创建context
向子组件提供context
子孙组件使用
useRef
引入useRef
创建ref
注册ref
使用ref
示例
以上就是关于React Hook介绍与使用心得全部的内容,包括:React Hook介绍与使用心得、从0搭建React+antd+TypeScript+Umi Hooks+Mobx前端框架、useReducer 和 useState等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)