如何掌握React Hook的用法,常用的有哪些
Admin 2022-07-20 群英技术资讯 434 次浏览
用法示例:
// 计数器 import { useState } from 'react' const Test = () => { const [count, setCount] = useState(0); return ( <> <h1>点击了{count}次</h1> <button onClick={() => setCount(count + 1)}>+1</button> </> ); } export default Test
PS:class组件中this.setState更新是state是合并, useState中setState是替换。例如:
// 错误示例 import { useState } from 'react' const Test = () => { const [counts, setCounts] = useState({ num1: 0, num2: 0 }); return ( <> <h1>num1:{counts.num1}</h1> <h1>num2:{counts.num2}</h1> <button onClick={() => setCounts({ num1: counts.num1 + 1})}>num1+1</button> <button onClick={() => setCounts({ num2: counts.num2 + 1})}>num2+1</button> </> ); } export default Test
可以看到useState中setState是替换,不会合并,正确更新:
import { useState } from 'react' const Test = () => { const [counts, setCounts] = useState({ num1: 0, num2: 0 }); return ( <> <h1>num1:{counts.num1}</h1> <h1>num2:{counts.num2}</h1> <button onClick={() => setCounts({ ...counts, num1: counts.num1 + 1})}>num1+1</button> <button onClick={() => setCounts({ ...counts, num2: counts.num2 + 1})}>num2+1</button> </> ); } export default Test
用法示例,在class组件中如果需要在组件挂载后和数据更新后做同一件事,我们会这样做:
componentDidMount() { // 做一些事 } componentDidUpdate() { // 做一些事 }
可以看出来,如果逻辑复杂后,代码看起来不优雅,且容易造成逻辑混乱,而使用useEffect:
useEffect(() => { // 做一些事 });
此刻已经看到了useEffect的基本用法,除此之外,他还可以绑定触发更新的依赖状态,默认是状态中任何数据发生变化副作用都会执行,如:
import { useState, useEffect } from 'react' const Test = () => { const [count1, setCount1] = useState(0); const [count2, setCount2] = useState(0); useEffect(() => { console.log('useEffect触发了') }); return ( <> <h1>count1:{count1}</h1> <h1>count2:{count2}</h1> <button onClick={() => setCount1(count1 + 1)}>count1+1</button> <button onClick={() => setCount2(count2 + 1)}>count2+1</button> </> ); } export default Test
将上述代码useEffect第二个参数传入需要绑定的状态,可绑定多个:
// 语法:useEffect(回调函数,[依赖值]) useEffect(() => { console.log('useEffect触发了') }, [count1]);
可以看到,只有绑定的count1发生变化才会触发,如果传空数组则任何状态发生变化都不会触发,此时useEffect的作用就类似class组件中的componentDidMount,所以发送请求通常也会在此执行。
在上面的操作中都不用清理的副作用,然而,有些副作用是需要去清理的,不清理会造成异常甚至内存泄漏,比如开启定时器,如果不清理,则会多次开启,从上面可以看到useEffect的第一个参数是一个回调函数,可以在回调函数中再返回一个函数,该函数可以在状态更新后第一个回调函数执行之前调用,具体实现:
useEffect(() => { // 设置副作用 return () => { // 清理副作用 } });
React.createContext();创建一个TestContext对象
TestContext.Provider包裹子组件
数据放在<TestContext.Provider value={value}>的value中
子组件中通过useContext(TestContext)获取值
import React, { useContext, useState } from 'react'; const TestContext = React.createContext(); const Parent = () => { const [value, setValue] = useState(0); return ( <div> {(() => console.log("Parent-render"))()} <button onClick={() => setValue(value + 1)}>value + 1</button> <TestContext.Provider value={value}> <Child1 /> <Child2 /> </TestContext.Provider> </div> ); } const Child1 = () => { const value = useContext(TestContext); return ( <div> {(() => console.log('Child1-render'))()} <h3>Child1-value: {value}</h3> </div> ); } const Child2 = () => { return ( <div> {(() => console.log('Child2-render'))()} <h3>Child2</h3> </div> ); } export default Parent
至此数据实现共享了,但是可以看到在TestContext中的共享数据只要发生变化,子组件都会重新渲染,Child2并没有绑定数据,不希望他做无意义的渲染,可以使用React.memo解决,实现:
const Child2 = React.memo(() => { return ( <div> {(() => console.log('Child2-render'))()} <h3>Child2</h3> </div> ); });
语法:
// useCallback(回调函数,[依赖值]) const handleClick = useCallback(()=> { // 做一些事 }, [value]);
useCallback返回的是一个 memoized(缓存)函数,在依赖不变的情况下,多次定义的时候,返回的值是相同的,他的实现原理是当使用一组参数初次调用函数时,会缓存参数和计算结果,当再次使用相同的参数调用该函数时,会直接返回相应的缓存结果。
优化性能例子:
import React, { useState, useCallback, memo } from 'react'; const Parent = () => { const [value1, setValue1] = useState(0); const [value2, setValue2] = useState(0); const handleClick1 = useCallback(()=> { setValue1(value1 + 1); }, [value1]); const handleClick2 = useCallback(()=> { setValue2(value2 + 1); }, [value2]); return ( <> {(() => console.log("Parent-render"))()} <h3>{value1}</h3> <h3>{value2}</h3> <Child1 handleClick1={handleClick1} /> <Child2 handleClick2={handleClick2} /> </> ); } const Child1 = memo(props => { return ( <div> {(() => console.log("Child1-render"))()} <button onClick={() => props.handleClick1()}>value1 + 1</button> </div> ); }); const Child2 = memo(props => { return ( <div> {(() => console.log("Child2-render"))()} <button onClick={() => props.handleClick2()}>value2 + 1</button> </div> ); }); export default Parent
useCallback返回的是一个memoized回调函数,仅在其中绑定的一个依赖项变化后才更改可防止不必要的渲染,在跨组件共享数据中举例的事件是在父组件中点击触发,而现在是使用状态提升,在父组件中传递方法供子组件调用,每次render时函数也会变化,导致子组件重新渲染,上面例子useCallback将函数进行包裹,依赖值未发生变化时会返回缓存的函数,配合React.memo即可优化无意义的渲染。
语法:
// useMemo(回调函数,[依赖值]) useMemo(() => { // 做一些事情 },[value]);
先看一个例子:
import React, { useState } from 'react' const Test = ()=> { const [value, setValue] = useState(0); const [count, setCount] = useState(1); const getDoubleCount = () => { console.log('getDoubleCount进行计算了'); return count * 2; }; return ( <div> <h2>value: {value}</h2> <h2>doubleCount: {getDoubleCount()}</h2> <button onClick={() => setValue(value + 1)}>value+1</button> </div> ) } export default Test
可以看到getDoubleCount依赖的是count,但value发生变化它也重新进行了计算渲染,现在只需要将getDoubleCount使用useMemo进行包裹,如下:
import React, { useState, useMemo } from 'react' const Test = ()=> { const [value, setValue] = useState(0); const [count, setCount] = useState(1); const getDoubleCount = useMemo(() => { console.log('getDoubleCount进行计算了'); return count * 2; },[count]); return ( <div> <h2>value: {value}</h2> <h2>doubleCount: {getDoubleCount}</h2> <button onClick={() => setValue(value + 1)}>value+1</button> </div> ) } export default Test
现在getDoubleCount只有依赖的count发生变化时才会重新计算渲染。
useMemo和useCallback的共同点:
useMemo和useCallback的区别:
6、useRef用法:例如要实现点击button按钮使input输入框获得焦点:
import React, { useState, useMemo } from 'react' const Test = ()=> { const [value, setValue] = useState(0); const [count, setCount] = useState(1); const getDoubleCount = useMemo(() => { console.log('getDoubleCount进行计算了'); return count * 2; },[count]); return ( <div> <h2>value: {value}</h2> <h2>doubleCount: {getDoubleCount}</h2> <button onClick={() => setValue(value + 1)}>value+1</button> </div> ) } export default Test
这样看起来非常像React.createRef(),将上面代码中的useRef()改成React.createRef()也能实现同样的效果,那为什么要设计一个新的hook?难道只是会了加上use,统一hook规范?
事实上,它们确实不一样。
官网的说明如下:
useRef returns a mutable ref object whose .current property is initialized to the passed
argument (initialValue). The returned object will persist for the full lifetime of the component.
翻译:
简单来说,useRef就像一个储物箱,你可以随意存放任何东西,再次渲染时它会去储物箱找,createRef每次渲染都会返回一个新的引用,而useRef每次都会返回相同的引用。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
这篇文章我们来了解jQuery如何实现商品筛选功能,如果经常购物的朋友对于商品的筛选功能应该都不陌生吧,能帮助我们快速的找到所需的商品,那么这个功能究竟是如何实现的呢?下文给大家分享了两种实现思路和方法,感兴趣的朋友就继续往下看吧。
这篇文章主要介绍js实现上传图片到服务器的功能,下文有实现的代码以及注释,对大家学习怎样实现上传图片到服务器有一定的帮助,感兴趣的朋友可以借鉴参考,接下来小编带着大家一起了解看看。
这篇文章通过实例代码给大家介绍了vue项目中添加electron的方法,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
今天我们来了解的是vue缓存页面怎样管理的内容,对于vue缓存页面的管理的问题的就是什么时候销毁及如何销毁,那么具体怎样做呢?下面跟随小编一起来了解看看吧。
本文主要介绍了JavaScript中let与const命令使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008