1、useState:让函数式组件拥有状态用法示例:
// 计数器import { useState } from 'react'const Test = () => {const [count, setCount] = useState(0);return (<><h1>点击了{count}次</h1><button onClick={() => setCount(count + 1)}>+1</button></>);}export default TestPS: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 Test2、useEffect:副作用,取代生命周期用法示例,在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的第一个参数是一个回调函数,可以在回调函数中再返回一个函数,该函数可以在状态更新后第一个回调函数执行之前调用,具体实现:
【6个常见hook React Hook用法详解】
useEffect(() => {// 设置副作用return () => {// 清理副作用}});3、useContext:跨组件共享数据React.createContext();创建一个TestContext对象TestContext.Provider包裹子组件
数据放在<TestContext.Provider value=https://tazarkount.com/read/{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=https://tazarkount.com/read/{value}>{(() => 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解决,实现:

文章插图
4、useCallback:性能优化语法:
优化性能例子:

文章插图
useCallback返回的是一个memoized回调函数,仅在其中绑定的一个依赖项变化后才更改可防止不必要的渲染,在跨组件共享数据中举例的事件是在父组件中点击触发,而现在是使用状态提升,在父组件中传递方法供子组件调用,每次render时函数也会变化,导致子组件重新渲染,上面例子useCallback将函数进行包裹,依赖值未发生变化时会返回缓存的函数,配合React.memo即可优化无意义的渲染 。
5、useMemo:性能优化语法:

文章插图
可以看到getDoubleCount依赖的是count,但value发生变化它也重新进行了计算渲染,现在只需要将getDoubleCount使用useMemo进行包裹,如下:

文章插图
现在getDoubleCount只有依赖的count发生变化时才会重新计算渲染 。
useMemo和useCallback的共同点:
事实上,它们确实不一样 。
官网的说明如下:

文章插图
简单来说,useRef就像一个储物箱,你可以随意存放任何东西,再次渲染时它会去储物箱找,createRef每次渲染都会返回一个新的引用,而useRef每次都会返回相同的引用 。

文章插图
至此数据实现共享了,但是可以看到在TestContext中的共享数据只要发生变化,子组件都会重新渲染,Child2并没有绑定数据,不希望他做无意义的渲染,可以使用React.memo解决,实现:
const Child2 = React.memo(() => {return (<div>{(() => console.log('Child2-render'))()}<h3>Child2</h3></div>);});
文章插图
4、useCallback:性能优化语法:
// 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即可优化无意义的渲染 。
5、useMemo:性能优化语法:
// 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计算结果是return回来的值,通常用于缓存计算结果的值
- useCallback计算结果是一个函数,通常用于缓存函数
import React, { useRef } from 'react';const Test = () => {const inputEl = useRef();return (<><input ref={inputEl} /><button onClick={() => inputEl.current.focus()}>focus</button></>);}export default Test这样看起来非常像React.createRef(),将上面代码中的useRef()改成React.createRef()也能实现同样的效果,那为什么要设计一个新的hook?难道只是为了加上use,统一hook规范?事实上,它们确实不一样 。
官网的说明如下:
useRef returns a mutable ref object whose .current property is initialized to the passedargument (initialValue). The returned object will persist for the full lifetime of the component.翻译:
文章插图
简单来说,useRef就像一个储物箱,你可以随意存放任何东西,再次渲染时它会去储物箱找,createRef每次渲染都会返回一个新的引用,而useRef每次都会返回相同的引用 。
- 春季老年人吃什么养肝?土豆、米饭换着吃
- 三八妇女节节日祝福分享 三八妇女节节日语录
- 老人谨慎!选好你的“第三只脚”
- 校方进行了深刻的反思 青岛一大学生坠亡校方整改校规
- 脸皮厚的人长寿!有这特征的老人最长寿
- 长寿秘诀:记住这10大妙招 100%增寿
- 春季老年人心血管病高发 3条保命要诀
- 眼睛花不花要看四十八 老年人怎样延缓老花眼
- 香槟然能防治老年痴呆症? 一天三杯它人到90不痴呆
- 老人手抖的原因 为什么老人手会抖
