HookHook是React16.8.0的新特性。Hooks允许你在没有类的情况下使用更多的React特性。钩子不能在类组件中使用。使用规则:Hook只能在函数的最外层调用。不要在循环、条件或子函数中调用。Hooks只能在React的函数式组件中调用。不要从其他JavaScript函数调用。StateHookuseState使用useState在函数组件中使用状态,而不使用类组件。可以通过多次调用声明多个状态参数:useState()方法中唯一的参数是初始状态。返回值:当前状态和更新状态的函数。功能更新:如果需要使用以前的状态计算新状态,可以将一个函数传递给setState。此函数将采用先前的状态并返回更新后的值。functionCounter({initialCount}){const[count,setCount]=useState(initialCount)return(<>Count:{count}setCount(initialCount)}>重置setCount((prevCount)=>prevCount+1)}>+setCount((prevCount)=>prevCount-1)}>->)}EffectHookEffectHook允许你在函数组件中进行副作用操作(React组件中的数据获取、订阅或手动修改DOM。我们统称这些操作为“副作用”,或简称为For“功能”。)useEffect可以将useEffectHook看成是三个函数的组合:componentDidMount、componentDidUpdate和componentWillUnmount。useEffect将在每次渲染后执行(在第一次渲染后和每次更新后),如果您的效果返回一个函数,React将在组件卸载时调用它以执行清理。useEffect可以在组件中多次调用。Hook允许我们根据代码的用途将它们分开。React会按照effect声明的顺序依次调用组件中的各个effect。在哪里使用:在组件内部调用useEffect。将useEffect放在组件中可以让我们直接访问效果中的计数状态变量(或其他道具)。性能优化:useEffect的第二个可选参数允许您告诉React如果某些值在重新渲染之间没有改变,则跳过调用effect。确保该数组包含外部作用域中随时间变化并用于效果的所有变量//仅在计数变化时更新useEffect(()=>{document.title=`Youclicked${count}times`},[count])//useEffect(()=>{console.log("1")return()=>{console.log("2")}}仅在组件首次渲染且组件销毁时执行[])示例代码详细解释useState和useEffect://介绍React中的useStateHook。它让我们在函数组件中存储内部状态//importuseEffectimportReact,{useState,useEffect}from"react"functionExample(props){//声明一个名为count的状态变量并将其设置为0const[count,setCount]=useState(0)//声明第二个状态const[isOnline,setIsOnline]=useState(null)//不需要清除的效果useEffect(()=>{//设置文档的标题包含消息ofthenumberofclicks.document.title=`Youclicked${count}times`})//需要清除的效果useEffect(()=>{functionhandleFn(val){setIsOnline(val)}//注册监听XXAPIsubscribe(handleFn)//清除监听return()=>{XXAPI.unsubscribe(handleFn)}})return(//readState:我们可以直接使用count
Youclicked{count}times
//UpdateState:你可以通过调用setCount
setCount(count+1)}>Clickme )}useLayoutEffect,其函数签名与useEffect相同,但它会在所有DOM变化后同步调用effect。它可用于读取DOM布局并同步触发重新渲染。useLayoutEffect内部的更新计划会在浏览器执行绘图之前同步刷新。尽可能使用标准useEffect以避免阻止视觉更新。与componentDidMount或componentDidUpdate不同,使用useEffect调度的效果不会阻止浏览器更新屏幕,这使您的应用程序看起来响应更快。在大多数情况下,效果不需要同步执行。在某些情况下(例如测量布局),您需要使用useLayoutEffectuseRefuseRef返回一个可变的ref对象,其.current属性被初始化为传递的参数(initialValue)。返回的ref对象在组件的整个生命周期中持续存在。functionTextInputWithFocusButton(){constinputEl=useRef(null)constonButtonClick=()=>{//`current`指向DOM上挂载的文本输入元素inputEl.current.focus()}return(<>聚焦输入>)}useRef()比ref属性更有用。保存任何可变值都很方便,类似于实例字段在类中的使用方式。当ref对象的内容发生变化时,useRef不会通知你。更改.current属性不会导致组件重新呈现。例如:functionTimer(){constintervalRef=useRef()useEffect(()=>{intervalRef.current=setInterval(()=>{//...})return()=>{clearInterval(intervalRef.current)}})//...}其他HookuseReduceruseReducer是useState的替代品,它以(state,action)=>newState的形式接收一个reducer,并返回当前状态及其匹配的dispatch方法。在某些场景下,useReducer比useState更适合,比如state逻辑复杂,包含多个子值,或者下一个state依赖于上一个state等。另外,使用useReducer还可以优化组件的性能触发深度更新,因为您可以将调度传递给子组件而不是回调函数。使用示例:constinitialState={count:0}functionreducer(state,action){switch(action.type){case"increment":return{count:state.count+1}case"decrement":return{count:state.count-1}默认值:thrownewError()}}functionCounter(){const[state,dispatch]=useReducer(reducer,initialState)return(<>Count:{state.count}dispatch({type:"increment"})}>+dispatch({type:"decrement"})}>->)}通过阅读React源码ReactFiberHooks.js发现useState就是对useReducer的封装://useStateexportfunctionuseState(initialState:(()=>S)|S):[S,Dispatch>]{returnuseReducer(basicStateReducer,//useReducer有一个特例来支持惰性useState初始化器(initialState:any))}//useReducerexport函数useReducer(reducer:(S,A)=>S,initialState:S,initialAction:A|无效|null):[S,Dispatch]{//...//...//...}利用useReducer实现forceUpdate:const[ignored,forceUpdate]=useReducer((x)=>x+1,0)functionhandleClick(){forceUpdate()}useMemo和useCallback可以用来传递参数和回调函数给子组件进行优化importReact,{useState,useMemo,useCallback}from"react"functionfnComponent(){const[count,setCount]=useState(0)const[name,setName]=useState("name")//不是每次都更新fnComponent就重新渲染Childconstconfig=useMemo(()=>{text:`countis${count}`},[count])consthandleButtonClk=useCallback(()=>{setCount((c)=>c+1)},[])return({count}