React Hooks钩子中API的使用示例分析
目录
- hooks是什么
- Hooks的作用
- 使用Hooks组件前后开发模式的对比
- Hooks使用策略
- 为什么要有Hooks
- useState
- useEffect使用
- useEffect依赖项
- 使用情景
- useMemo使用
- useMemo缓存组件方式
- useMemo和useEffect的区别
- useCallback使用
- useContext使用
- useRef使用
- 为什么在函数组件中无法使用ref
- 如何在类组件中使用ref属性
- 自定义hooks
hooks是什么
hooks理解字面意思就是钩子,是一些可以让你在函数组件里钩入 React state以及生命周期等特性的函数,可以让不编写class的情况下使用state以及其他的React特性
Hooks的作用
为函数组件提供状态,生命周期等原本在class组件中才提供的功能
Hooks只能在函数组件中使用
可以理解为通过Hooks为函数组件钩入class组件的特性
使用Hooks组件前后开发模式的对比
使用前(React v 16.8前):class组件(提供状态)+函数组件(展示内容)
使用后(React v 16.8后):Hooks(提供状态)+函数组件(展示内容)
Hooks使用策略
(1)react没有计划从React中移除class
(2)hook和现有代码可以同时工作,可以渐进式使用
不推荐直接使用Hooks大规模重构现有组件
推荐新功能使用Hooks,复杂功能实现不来,也可以继续使用class
(3)class组件相关的API在hooks里面可以不用
state setState 钩子函数,this相关用法
(4)原来学习的内容还是要用
JSX:{} onClick={} 、条件渲染、列表渲染、样式处理
组件:函数组件,组件通讯
react开发理念:单向数据流,状态提升
为什么要有Hooks
首先我们要了解react的本质,接着从函数组件和类组件进行分析优缺点
react本质:用于构建用户界面的javascript库,是对特定功能的封装,主要对url进行拆分
react组件的模型其实很直观,就是从model到view的映射,这里的model对应的是react的state和props
函数式组件的好处:
- 函数本身比较简单,更好的胜任根据状态来渲染url这件事
- hooks让函数组件内部有了维护状态的能力
- hooks带来了组件的逻辑复用的能力
class组件自身的问题:
- 在根据状态来渲染url这件事上,class组件并没有发挥它的重要功能
- 组件之间很少继承
- 组件之间很少相互访问
useState
作用:为函数组件提供state状态
步骤:
- 导入useState函数
- 调用useState函数,传入初始值,返回状态和修改状态的函数
- 使用:在jsx中展示状态,特定的时机调用修改状态的函数修改状态
- 定义state数据,返回一个数组,有两个值,第一个值,定义数据初始化的值,第二个值,修改数据函数,可以做到页面的响应式
useState两种格式:
格式1:传入值 useState(0) 或useState('abc')
格式2:传入回调,useState({上一次的值}=>{return 新值})
- 回调函数的返回值就是状态的当前值
- 回调函数只会触发一次
代码展示
import React, { useState } from 'react' export default function UseState() { let [count,setCount]=useState(10) // 他是异步的操作,在页面数据会进行更新,但是下面打印的数据是没有更新,原因是因为他是异步的 const plus=()=>{ setCount(count+5) } return ( <div> {/* 函数组件中没有this指向,我们可以直接调用 */} <div>{count}</div> <button onClick={()=>setCount(count++)}>加加</button> <button onClick={plus}>plus</button> </div> ) }
注意:上面必须引入useState 使用
useEffect使用
函数式组件:
主作用:就是根据数据(state/props)渲染ul
副作用:数据请求,手动修改DOM、开启定时器、清空定时器、localStorage操作等
副作用:只要是渲染数据之外的操作都是副作用,副作用不一定非要写在useEffect里,可以写外面,但是写useEffect会起到约束作用
执行时机(以下两种情况会执行Effect):
- 组件挂载时,执行一次(相当于生命周期中componentDidMount)
- 组件更新时,可能执行多次(相当于生命周期中的componentDidUpdate)
在实际开发中,副作用是不可避免的,react专门用useEffect来处理组件中的副作用
useEffect依赖项
有两个参数:(参数一:(副作用函数),参数二:(执行副作用函数的依赖项,他决定了什么时候执行参数1(副作用)))
- 如果不设置第二个参数,那么每次页面更新他都会执行
- 参数是空数组,永远只执行第一次
- 指定依赖项,执行时机(初始化执行一次,依赖项发生变化执行一次)可以有多个依赖项
- useEffect() 代替三个生命周期函数 componentDidMount compoentDidUpdate 钩子函数, componentWillUnmount 生命周期
使用情景
- 事件绑定
- 发送请求获取数据等 axios ajax
useEffect(()=>{ 逻辑}) 页面数据只要更新就会触发useEffect() useEffect(()=>{},[]) useEffect() 只执行一次,只有页面第一次加载的时候触发,componentDidMount useEffect(()=>{}, [num,count]) 监听数据改变执行,num和count发生变化的时候触发。compoentDidUpdate useEffect(()=>{ return ()=>{ console.log("相当于compoentDidUnmount") } },[]) //回调函数返回函数,返回的函数相当于销毁生命周期函数。
useMemo使用
相当于vue中计算属性,他一般需要返回一个结果,具有缓存性的效果
useMemo他是在DOM更新的时候触发的,useEffect() DOM更新后触发的副作用函数
缓存复杂运算的结果,避免重复调用执行
useMemo页面一般会渲染第一次执行后的结果
代码展示
import React, { useMemo, useState } from 'react' export default function UseState() { let [count,setCount]=useState(10) // useMemo必须有返回值,而且他是在dom更新发生变化,比useEffect执行的快,useEffect是dom更新完才执行的,监听count值变化 const double=useMemo(()=>{ console.log('useMemo触发'); return count+6 },[count]) return ( <div> {/* 函数组件中没有this指向,我们可以直接调用 */} <div>{count} {double}</div> <button onClick={()=>setCount(count*2)}>count二倍</button> </div> ) }
useMemo缓存组件方式
第一种通过useMemo缓存组件
//useMemoe缓存组件 function Home() { let [count,setcount] = useState(10) let [num,setnum] = useState(20) //通过useMemoe对组件进行缓存,避免父组件中根子组件无关数据更新导致子组件的重新渲染。 let theme = useMemo(()=>{ return ( <Theme count={count}></Theme> ) },[count]) return ( <div> <h3 >count--{count}</h3> <button onClick={()=>setcount(count+1)}>count++</button> <h3 >num--{num}</h3> <button onClick={()=>setnum(num+1)}>num++</button> <hr /> {theme} </div> ) } function Theme(props){ useEffect(()=>{ console.log("子组件渲染") }); return ( <h3>子组件接受数据{props.count}</h3> ) }
第二种通过react自带的memo方法
memo是一个高阶组件方法,接受一个组件作为参数,根据组件传递的参数值,对组件进行缓存,避免组件的多余的DOM渲染效果
function Home() { let [count,setcount] = useState(10) let [num,setnum] = useState(20) return ( <div> <h3 >count--{count}</h3> <button onClick={()=>setcount(count+1)}>count++</button> <h3 >num--{num}</h3> <button onClick={()=>setnum(num+1)}>num++</button> <hr /> <Theme count={count}></Theme> </div> ) } //通过memo对组件进行缓存,避免父组件中根子组件无关数据更新导致子组件的重新渲染。 const Theme = memo((props)=>{ useEffect(()=>{ console.log("子组件渲染") }); return ( <h3>子组件接受数据{props.count}</h3> ) })
useMemo和useEffect的区别
不同点:
useEffect是在dom更新后触发的副作用函数,他被称为副作用函数就是因为他在我们更新完成之后才通知我们,类似于马后炮,useEffect不需要返回值,他没有数据缓存的作用
useMemo是在dom更新时触发的,useMemo必须要返回数据的结果,他是具有缓存数据的作用
共同点:
如果非要说共同点,那么他俩都有两个参数,并且第二个参数如果是空[]的话,那么他的数据只会执行一次,也可以给他设置监听项,[监听值的名称],第二个参数是可选参数,也可以不写,不写就是页面只要发生一点改变,就会重新渲染一次,浪费数据更新的性能
useCallback使用
在上述的例子中如果我们传递的是普通的变量,缓存后,父组件更新的话不会导致子组件的更新,但是如果你传递的是一个函数,父组件的每次更新都会重新调用一次函数,这个时候就会不同函数调用,会导致子组件的重新渲染,如果我们还要做组件缓存,我们可以使用useCallback() , 可以对函数进行一个缓存的作用
代码展示
function Home() { let [count,setcount] = useState(10) let [num,setnum] = useState(20) const handlerCount = ()=>{ console.log(count); } const callback = useCallback(()=>{ handlerCount(); },[count]); return ( <div> <h3 >count--{count}</h3> <button onClick={()=>setcount(count+1)}>count++</button> <h3 >num--{num}</h3> <button onClick={()=>setnum(num+1)}>num++</button> <hr /> <Theme count={count} handle={callback}></Theme> </div> ) } //通过memo对组件进行缓存,避免父组件中根子组件无关数据更新导致子组件的重新渲染。 const Theme = memo((props)=>{ useEffect(()=>{ console.log("子组件渲染") }); return ( <div> <h3>子组件接受数据{props.count}</h3> <button onClick={()=>props.handle()}>点击</button> </div> ) })
useMemo,memo,useCallback如何提升性能的(面试题必问)?
useMemo主要的作用是缓存复杂运算的数据返回的结果,有两个参数,第二个参数可以定义要监听的数据,并且需要返回,跟useEffect第二个参数的作用类同
当父组件的组件更新的时候会导致子组件的重新渲染,但是如果父组件的更新的数据没有传递给子组件的话,这时候还让子组件重新渲染的话,会导致组件更新性能消耗比较大
所以说这个时候我们可以使用useMemo,或者使用react内置的memo方法对子组件进行缓存,这样只有父组件更新跟子组件有关的数据时才会导致子组件重新渲染,从而提高组件的渲染性能
但是如果我们给子组件传递的是一个方法的时候,上面的useMemo,memo方法缓存就不起作用了,原因是父组件每更新一次会导致方法的重新调用,进而导致子组件的重新更新,这时候我们可以用到useCallback对传递的方法进行缓存,监听数据更新后才会重新调用方法,从而提高组件的渲染性能
useContext使用
用来获取context状态树的内容数据的Hooks的APi,相当于class组件中static contextType = react.createContext创建的对象内容
代码展示
import React, { useContext, useState } from 'react'; //useContext用于获取context状态树的值 // 首先创建一个空的context对象 const ThemContext =React.createContext(); function UseState() { let [color,setColor]=useState('#ff0000') return ( <div> {/* 通过Provider传过来一个value值,是一个对象 */} <ThemContext.Provider value={{color:color}}> <button onClick={()=>setColor('pink')}>粉色</button> <button onClick={()=>setColor('blue')}>蓝色</button> <button onClick={()=>setColor('green')}>绿色</button> <Son></Son> </ThemContext.Provider> </div> ) } // 子组件 function Son(props) { // 通过useContext获取父组件传过来的值 const context=useContext(ThemContext) return ( <div> {/* 然后对他进行样式绑定 */} <h3 style={context}>hello,react</h3> </div> ) } export default UseState
useRef使用
useRef 作用相当于class组件React.createRef()的作用,用于创建ref节点对象的内容
//创建一个ref对象的内容 let inp = useRef(null); const setVal =()=>{ console.log(inp.current.value); } <input placeholder='输入内容' ref={inp} onChange={setVal}/>
为什么在函数组件中无法使用ref
普通的类组件有实例所以可以用React。createRef()挂载到节点或者组件上,然后通过this获取到该节点或组件,正常情况下ref是不能挂到函数组件上,因为函数组件没有实例
如何在类组件中使用ref属性
我们可以通过forwardRef将ref父类的ref作为参数传入函数式组件中
forwardRef是一个高阶函数,跟memo一样
还有一种方法就是把函数组件改成类组件
function Home() { //定义一个初始化变量 let inpRef = useRef(null); const getTheme = ()=>{ console.log(inpRef); } return ( <div> <input placeholder='输入内容'/> <button onClick={getTheme}>获取子组件对象</button> <hr /> <Theme ref={inpRef}/> </div> ) } const Theme = forwardRef(function(props,ref){ return ( <h3 ref={ref}>文字内容显示</h3> ) })
自定义hooks
写一个自定义页面标题的效果,路由中使用
import { useEffect } from "react"; //自定义显示标题的Hooks的方法内容 const useTitle = (title) => { useEffect(() => { document.title = title; return ()=>{ document.title="React 页面" } }, []); return; } export { useTitle };
import { useTitle } from "../context/hooksApi" export default function My(){ useTitle("个人中心") return ( <div> <h3>个人中心</h3> </div> ) }
还有其他的自定义hooks API方法,这举例的是一种
到此这篇关于React Hooks钩子中API的使用示例分析I的文章就介绍到这了,更多相关React Hooks API内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!