useState
const [ count ,setCount] = useState(parameter)
- count保存useState中的参数,参数可以为传入普通的参数,也可以传入function和array,在没有传入参数时为undefined
- setCount在改变count中的值时使用
- hook只能在React函数组件或者自定义hook中使用,不能在js函数中直接使用
- useState最好不要在循环,条件判断或者子函数中调用,因为useState保存的数据使用链表的数据结构进行保存的,在上面的几种条件下使用useState会使链表断裂,数据会错乱
- 在React钩子函数及合成事件中,表现为异步
- 在setTimeout和setInterval及DOM原生事件中表现为同步
useEffect
useEffect(() => {
console.log('开始订阅')
return () => {
console.log('取消订阅')
}
}, [count])
- 主要用于模拟类组件中的生命周期,需要传入一个函数,在函数体类似类组件中componentDidmount函数,return返回的也是一个函数,类似于类组件中componentWillUnmount函数,我们可以在函数体中订阅某些事件,在return返回函数中取消订阅事件
- hook是可以添加多个相同的hook函数,这就意味着不必像类组件中所有的订阅事件和网络请求都放到componentWillUnmount,可以使用相同的hook将不同的事件进行抽取
- useEffect的第二个参数是一个数组,里面主要放函数体中的一些变量,当这些变量发生改变时,函数才会被重新执行,如果不希望依赖任何变量时,传入空的数组就行
useContext
在组件中使用共享的Context有两种方式
- 类组件可以通过 类名.contextType = MyContext方式,在类中获取context
- 多个Context或者在函数式组件中通过 MyContext.Consumer 方式共享context
- 当存在多个context时的方式会存在大量的嵌套
Context Hook允许我们通过Hook来直接获取某个Context的值
const maincontext = useContext(Maincontext) // 直接获取传入的value值
//简化context获取值得操作,直接通过usecontext就可以获取到传入的value值
//但是第一步操作仍然不能少
const usecontext = useContext(Usecontext)
console.log(maincontext, usecontext)
useReducer
- useReducer主要用于在相同事件,不同方法时,代替useState,避免过多的useState方法
- 要注意的是useReducer代替的是useState,不是redux,useReducer里面的状态是不能共享的
import React, { useState, useReducer } from 'react'
function reducer(state, action) {
switch (action.type) {
case "add":
return { ...state, count: state.count + 1 };
case "sub":
return { ...state, count: state.count - 1 }
default:
return state
}
}
export default function Home() {
// const [count, setCount] = useState(0)
const [state, dispatch] = useReducer(reducer, { count: 0 }) //拆分usestate
//将改变state状态统一进行管理
return (
<div>
<h2>当前计数:{state.count}</h2>
<button onClick={e => dispatch({ type: "add" })}>+1</button>
<button onClick={e => dispatch({ type: "sub" })}>+1</button>
</div>
)
}
useCallback 和 useMemo
- 这两个的作用都是一样的,都是为了对子组件传递相同内容的函数或者对象时,让子组件不要重新进行渲染
- 区别就是useCallback传入的是函数,可以添加相应的依赖项
const sub = useCallback( ///子组件在没有数据改变情况下不会重新渲染
() => {
console.log("sub被执行")
setCount(count - 1)
}, [count],
)
- useMemo返回的可以是对象,数组,函数,也可以添加相应的依赖
//返回的是对象
const info = useMemo(() => {
return { name: "jack", age: 18 };
}, []);
useRef
常用的ref是两种用法
- 用法一:引入DOM(或者组件,但是需要是class组件)元素
- 用法二:保存一个数据,这个对象在整个生命周期中可以保存不变
import React, { useRef, useState, useEffect } from 'react'
export default function UseRefDemo1() {
const divRef = useRef()
const iptRef = useRef()
const [count, setCount] = useState(0)
const countRef = useRef(count) //只能保持初始值,
useEffect(() => { //通过useEffect可以保存上一次的值
countRef.current = count
}, [count])
function changeBtn() {
divRef.current.innerHTML = "world"
iptRef.current.focus()
}
return (
<div>
<div ref={divRef}>hello</div>
<input ref={iptRef} type="" name="" id="" />
<button onClick={e => changeBtn()}>点击</button>
<h2 >CountRef:{countRef.current}</h2>
<h2>count: {count}</h2>
<button onClick={e => setCount(count + 1)}>+1</button>
</div>
)
}
useImperativeHandle
理解useImperativeHandle的用法先来看一下ref和forwardRef结合使用
- 通过forwardRef可以将ref转发到子组件
- 子组件拿到父组件中创建的ref,绑定到自己的某一个元素中
import React, { forwardRef, useRef, useImperativeHandle } from 'react'
//父组件通过ref建立联系,子组件通过forwardRef接收ref
const Btn = forwardRef((props, ref) => {
const forwardRef = useRef()
//下面需要利用子组件的ref
return <input ref={forwardRef} type="text" />
})
export default function RefDemo() {
const btnRef = useRef()
return (
<div>
<Btn ref={btnRef} ></Btn>
<button onClick={e => btnRef.current.focus()}>点击</button>
</div>
)
}
- 这个例子就展示了ref和forwardRef的结合使用,看起来其实是,没有什么问题的,但是不够严谨,父组件不仅仅能拿到子组件的focus方法,还能拿到其他的方法,但是这里只需要focus方法,react为了能让代码更加严谨一点造出来一个useImperativeHandle方法,这个方法主要是让父组件只能拿到他想要的方法,其他不要的方法不需要暴露给子组件,下面对上面的代码进行一个更加严谨的写法
import React, { forwardRef, useRef, useImperativeHandle } from 'react'
//父组件通过ref建立联系,子组件通过forwardRef接收ref
//useImperativeHandle 作用只暴露父组件需要的子组件方法和属性
const Btn = forwardRef((props, ref) => {
const forwardRef = useRef()
useImperativeHandle(ref, () => ({
focus: () => { //父组件只需要focus方法,只暴露子组件focus方法
forwardRef.current.focus();
}
}), [forwardRef.current]) //子组件的ref发生更新时重新渲染
//下面需要利用子组件的ref
return <input ref={forwardRef} type="text" />
})
export default function RefDemo() {
const btnRef = useRef()
return (
<div>
<Btn ref={btnRef} ></Btn>
<button onClick={e => btnRef.current.focus()}>点击</button>
</div>
)
}
-这里子组件就只暴露了focus方法,其他的方法是没有暴露的,让代码的逻辑性更加严谨
useLayoutEffect
-
useLayoutEffect看起来和useEffect非常的相似,事实上他们也只有一点区别而已
- useEffect会在渲染的内容更新到DOM上后执行,不会阻塞DOM的更新
- useLayoutEffect会在渲染内容更新到DOM之前执行,会阻塞DOM的更新
- 如果我们希望在某些操作发生之后再更新DOM,那么应该将这个操作放到useLayoutEffect