React Hooks

355 阅读2分钟

useState

相当于类组件的state,useState 返回一个 state,以及更新 state 的函数(setState)。

function App(){
	const [n,setN]=React.useState(0)
    const [msg,setMsg]=React.useState({name:'cris',age:18})
    
    addN=()=>{
    	setN(i=>i+1)
    }
    
    addAge=()=>{
    	setMsg(obj=>({...obj,age:obj.age+1}))
    }
    return(
    	<div>{n}</div>
        <button  onClick={addN}>n+1</button>
    )
}

在初始渲染期间,返回的状态 (state) 与传入的第一个参数 (initialState) 值相同。

setState 函数用于更新 state;它接收一个新的 state 值并将组件的一次重新渲染加入队列,待当前代码执行完才会重新渲染页面。

  • 函数组件的setState 不会自动合并更新对象,用...操作浮先拷贝再修改;
  • useState不可用在循环或者条件语句中,因为每此渲染的useState顺序不能改变;
  • setState((i)=>{/.../})可以连续执行,setState(n+1)不能在一个函数里执行两遍。

useEffect

副作用,用于函数组件中代替componentDidMount、componentDidUpdate、componentWillUnmount。

function App(){
	const [n,setN]=React.useState(0)
	useEffect(()=>{
    	//组件首次加载到页面执行的函数
    },[])
    useEffect(()=>{
    	//n变化后执行函数
    },[n])
    useEffect(()=>{
    	return ()=>{
    		//组件销毁前执行的函数
    	}
    },[])
}

useRef

  1. 用于组件获取DOM元素
function App(){
	const divRef=React.useRef() //创建一个{current:"",...}对象
    useEffect(()=>{
    	const {width}=divRef.current.getBoundingClientRect()
        console.log(width)
    },[])
    return (
    	<div ref={divRef}>A word</div>  //应用divRef
    )
}
  1. 获取之前的props或者state,但触发useRef().current变化并不会刷新页面
function usePrevious(state){  //传入现在的state值
	const ref=React.useRef(null)
    useEffect(()=>{  //页面更新后执行下面函数
    	ref.current=state
    },[state])
    return ref.current
}

useContext

获取上下文关系,简单来说就像Vue的provid与inject,达到父子组件的通信。

/*App.css*/
.red{
	color:red
}
.green{
	color:green
}
import './App.css'

const themeContext=React.createContext()

function App(){
	const [theme,setTheme]=React.useState()
    return (
    	<themeContext.Provider value={theme,setTheme}>
        	<div className={theme}>
            	<Child/>
            </div>
        <themeContext.Provider/>
    )
}

function Child(){
	const {theme,setTheme}=React.useContext(themeContext)
    return (
    	<button onClick={()=>{setTheme('red')}}>red</button>
        <button onClick={()=>{setTheme('green')}}>green</button>
    )
}

useReducer

复杂类型的useState,一般用于表单的建立

  1. 创建初始值initValue
  2. 创建reducer=(state,action)=>{}
  3. 引用const [state,dispathch]=React.useReducer(reducer,initValue)
  4. 调用dispath({type:"xxx",...})

使用useReducer和useContext可代替Redux。

useLayoutEffect

与useEffect用法一致, 只是在页面渲染前执行,也就是beforeMount阶段,如果不是改变UI,就不要使用useLayoutEffect,因为该hooks会延长页面加载时间。

useMemo/useCallback

某个依赖变了才会调用函数

const fn=React.useMemo(()=>{
	return ()=>{console.log(m)}
},[m])

相当于

const fn=React.useCallback(()=>{
	console.log(m)
},[m])

forwardRef

如果在引用的函数组件上使用ref,必须使用forwardRef包裹该函数组件,将ref传入函数组件内部,看示例:

function App(){
	const btnRef=React.useRef(null)
	return (
    	<div>
        	<Child ref={btnRef}/> 
        </div>
    )
}

//由于props不包含ref,所以需要单独传入

const Child=React.forwardRef(  
	(props,ref)=>{   //父组件传入的ref值
    	return (
        	<button ref={ref}></button>
        )
    }
)

useImperativeHandle

对ref的封装,使用较少,名字取得晦涩。

function App(){
	const btnRef=React.useRef(null)
    useImperativeHandle(ref,()=>{
    	return{
        	x:()=>{btnRef.current.remove()},
            btnRef:btnRef   //真的btnRef
        }
    })
	return (
    	<button ref={btnRef}></button>
    )
}