一、useState(更新状态量)
-
使用场景:函数组件更新状态
-
写法:
const [state,setState]=useState(initialState) -
initialState代表state的初始状态;也可以写成()=>{}
-
setState一般放在事件处理函数
handleXXX(){ }和useEffect()中;有两种写法: a.setState(newState)b.setState(pre=>{return })
二、useEffect(副作用)
-
使用场景:用于处理组件中的effect,通常用于请求数据,事件处理,订阅等相关操作
-
写法:
import { useEffect } from 'react'
useEffect(() => {
// 副作用函数的内容
...
return ()=>{ /* 做清理工作*/ } // 清除函数,可写可不写
}, [depency])
-
return函数在组件销毁前执行,模拟类组件生命周期的 WillUnmount
-
useLayoutEffect在浏览器渲染前执行,useEffect在浏览器渲染完成后执行
-
第二个参数数组中写依赖参数,数组不写参数表示函数组件初始化时只执行一次,不写数组表示函数组件的初始化和每次更新都会执行
三、useRef(返回一个可变的ref对象)
-
使用场景:获取DOM元素、多次渲染之间共享数据
-
写法:
const xxx = useRef(initialValue) -
initialValue被赋初始值给其返回值的.current对象,.current对象保存着可变值;
-
ref对象与自建一个对象的区别是:useRef会在每次渲染时返回同一个ref对象,即返回的ref对象在组件的整个生命周期内保持不变。而自建对象每次渲染时都建立一个新的
-
挂载dom节点
<div ref={xxx}></div>,.current对象就拥有了dom元素的属性,常用的如失焦聚焦 -
挂载子组件
<Child ref={xxx} />,可以在子组件函数搭配forwradRef((props,ref)=>{})使用useImperativeHandle(ref,createHandle,[deps])来获取子组件的值
import { useRef } from 'react'
//父组件
const Parent=()=>{
const childRef=useRef(null)
console.log(childRef.current.getData())
return <Child ref={childRef} />
}
//子组件
const Child = forwardRef((props, ref) => {
const data=[1,2,3]
useImperativeHandle(ref, () => ({ getData, }));
const getData = () => {return data};
return <div>子组件</div>; })
四、useContext(上下文)
-
使用场景:跨组件传值
-
写法:
//在上级组件导入并调用createContext方法,得到Context对象,并导出
import { createContext } from 'react'
export const Context = createContext()
//在上级组件的jsx元素里用Context.Provider包裹需要接收数据的后代组件
const Parent=()=>{
const data='需要传递的数据';
const setData=()=>{};
const {Provider}=Context;
return (
<>
<div>父组件</div>
<Provider value={data,setData}>
<Child />
</Provider>
</>
)
}
//在需要获取公共数据的后代组件中,导入useContext,并按需获取需要的value
import React, { useContext } from 'react'
import { Context } from './index'
const Child = () => {
const {data,setData} = useContext(Context) // 这里的公共数据就是根组件value的值
return <div onClick={setData}>{data}</div>
}
五、useMemo 和 useCallback (解决使用React Hooks产生的无用渲染的性能问题)
-
使用场景:缓存计算结果(前者缓存计算结果的值,即避免在每次渲染时都进行高开销的计算;后者缓存函数,因为函数式组件每次任何⼀个 state 的变化整个组件都会被重新刷新,⼀些函数是没有必要被重新刷新的,此时就应该缓存起来,提⾼性能,减少资源浪费)
-
写法: useMemo:
let memo =useMemo(()=>{return xxx},[depency])
useCallback:const callback = useCallback(()=>{return ()=>{}},[depency])
import React, { useState, useCallback,useEffect, memo } from 'react';
const Parent = () =>{
const [count, setCount] = useState(1);
const [val, setVal] = useState('');
// 借助useCallback来返回函数,然后把这个函数作为props传递给子组件;这样,子组件就能避免不必要的更新
// 当count改变时才重新渲染callback,如果第二个参数传空数组,后续渲染只会记住第一次
const callback = useCallback(() =>{setCount(pre=>pre+1)} , []);
// 不缓存,每次 count 更新时都会重新创建
const add=()=>{setCount(pre=>pre+1)}
return (<>
<h4>父组件:{count}</h4>
<Child add={add} callback={callback} val={val}/>
<div>
<input value={val} onChange={e => setVal(e.target.value)}/>
</div>
</>)
}
//组件使用memo包裹可以减少渲染;如果子组件的pros没有发生变化,则不会重新渲染子组件
const Child= memo(({add, callback,val}) =>{
//只有当父组件的val改变时,才会触发更新
let memo=useMemo(()=>{
console.log('子组件更新新了');
return Math.floor(Math.random()*3)
},[val])
//没有缓存,由于每次都创建,memo 认为两次地址都不同,属于不同的函数,所以会触发 useEffect
useEffect(()=>{console.log('add')},[add]);
// 有缓存,memo 判定两次地址都相同,所以不触发 useEffect
useEffect(()=>{console.log('callback')},[callback]);
return <>
<h4>{memo}</h4>
<button onClick={add}>+1,不使用callback</button>
<br>
<button onClick={callback}>+1,使用callback</button>
</>
})
- 如果用函数或变量作为 props 传给子组件,请一定要用useMemo 和 useCallback,避免子组件的非必要渲染
六、useReducer(useState的代替方案,用于 state 复杂变化)
-
使用场景:单个组件状态管理,提供类似 Redux 的功能
-
写法:
const[state,dispatch]=useReducer(reducer,initialState) -
reducer 接受两个参数state和action ,然后返回一个状态 state 和 dispath,state 是返回状态中的值,而 dispatch 是一个可以发布事件来更新 state的函数 ,disptachd的参数对象属性通常为type和payload
import React, {useReducer} from 'react';
const initialState=0;
const reducer=(state,action)=>{
const { type, payload } = action;
switch(type){
case:'a':
return {
...state,
...payload
};
default:
break;
}
export default ()=>{
const[state,dispatch]=useReducer(reducer,initialState);
const handleClick = () => { const data = [1,2,3];dispatch({ type:'a', payload:data }) };
return <div onClick={handleClick}>123</div>
}
七、useDispatch(组件调用dispatch需要useDispatch来创建) 和 useSeletor (组件获取redux的状态)
-
使用场景:前者共享状态,返回Redux的store中对dispatch的引用,可执行redux中的方法;后者获取状态,返回Redux的store中提取state
-
写法: useDispatch:
const dispatch =useDispatch()
useSeletor:const {stateA,stateB...} = useSelector((state: any) => state['xxx'])
import { useDispatch,useSeletor} from 'react-redux'
export default ()=>{
const {stateA,stateB} = useSelector((state: any) => state['xxx']); //store里面对应的namespace名称
const dispatch =useDispatch();
const handleClick = () => {
const data = [1,2,3]
dispatch({
type:'xxx/xxx', //type里面写store里面对应的namespace名称然后对应的reducer名称
payload:data
})
};
return <div onClick={handleClick}>{stateA}-{stateB}</div>
}