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
- 用于组件获取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
)
}
- 获取之前的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,一般用于表单的建立
- 创建初始值
initValue - 创建
reducer=(state,action)=>{} - 引用
const [state,dispathch]=React.useReducer(reducer,initValue) - 调用
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>
)
}