Hook 是能让你在函数组件中“钩入” React 特性的函数(hook是react16.8的新增特性,让函数组件可以使用state以及其他react特性)
一、useState
useState用来创建state变量
const [state,setState]=React.useState(0)
const [state,setState]=React.useState({name:'frank',age:'18})
// 0或{name:'frank'}为state的初始值,setState函数可以改变state的值
setState(2)
setState({...state,name:'newName'})
// 由于react更新是重新生成一个新对象,react只会生成传入的对象,所以如果不想另一个属性遗失就必须使用将原本的对象展开放上去
二、useReducer
useReducer是useState的综合版
useReducer接受两个参数,一个操作函数,一个初始值
const [state,dispatch]=React.useReducer(fn,obj)
// 调用
dispatch({type:'name'}) //参数传给fn的action
函数
const fn =(state,action)=>{
// state为原始state;action为传过来的参数
return 新state(obj)的值
}
初始值
const obj={
name:'frank',
age:'18'
}
三、useContext
useContext上下文,上下文是局部(context.provider包裹)的全局变量
// 创建上下文
const Context = React.createContext(null)
// 使用context.provider圈定作用域
<Context.Provider value={{ n, setN }}>
app
<Father />
</Context.Provider>
// 使用context传过来的值
const Father = () => {
const { n, setN } = useContext(Context) // 使用上下文的值
const onButton = () => {
setN(n + 1)
}
return (
<div>
father:{n}
<button onClick={onButton}>+1</button>
</div>
)
}
注意:这个地方更改n的值界面也随之更改,并不是因为react的响应式,而是因为每次调用setN都会重新渲染App,发现n的值变了界面才变
四、useEffect
useEffect 使用副作用,名字取得不是很好理解,平替的名字可以是afterRender(渲染之后执行),
// 以下三个都会在第一次渲染执行一次
useEffect(() => {}) //任何元素变化都执行
useEffect(() => {},[n]) //n变化执行
useEffect(() => {},[]) //挂载执行
useEffect(() => {
return ()=>{} //消亡执行
},[])
通常情况下useEffect都是由上往下执行,但是useLayoutEffect在它之前执行
useLayoutEffect
useLayoutEffect是在Dom创建之后,渲染之前执行。原理如下:
useLayoutEffect.png
五、memo、useMemo、和useCallback
这三个api都是为了防多次渲染而来的
举个栗子,以下代码中m的值没有变,但是Child还是执行了。。怎么防止这种情况呢?
const App = () => {
const [n, setN] = useState(0)
const [m, setM] = useState('a')
return (
<div>
<div>grandfather</div>
<button onClick={() => { setN(i => i + 1) }}>+1</button>
<Father n={n} />
<Child m={m} />
</div>
)
}
const Father = (props) => {
console.log('father执行了')
return (
<div>father:{props.n}</div>
)
}
const Child = (props) => {
console.log('child执行了')
return (
<div>child:{props.m}</div>
)
}
- 将组件传给React.memo
const Child2 = React.memo(Child) //将Child2代替Child使用
// 或
const Child = memo(
() => {
return (
<div>child:{props.m}</div>
)
}
)
只是这么做有一个bug,那就是当props传递的是函数时,这个方法不生效。这时就要用到useMemo了
// 假如以下是传递的函数
const fn=React.useMemo(()=>{return ()=>{}},[m]) //当n变化时被传的组件才会执行
只是这么写是不是看着有点怪怪的。于是react提供了个语法糖,可以直接传个函数React.useCallback(fn,value)
const fn1 = React.useCallback(()=>{},[m])
其实这就有点类似于vue的computed了,有缓存当依赖的值变化才执行
六、useRef
useRef声明一个不变的值(这里说的不变是指内存地址不变)
// 声明
const count = useRef(0)
// 使用
count.current += 1
因为更改useRef的值不会导致app渲染,会造成结果变了UI没更新。解决:
const [n, setn] = useState(0)
// 调用一下
setn()
使用useState的特性重新(手动)render一下App
网友评论