注:下面hooks尽量不要套用在if判断里面,因为react会初始计算hooks的个数,如果后期因为一些判断导致数量有变化,会报错。如果非要在if里面使用,请保持if和else个数的相等
useState
useState可以代替类组件的setState,可以使用多个useState函数
let [count, setCount] = useState(0);
// 下面两种写法都可以
<div onClick={() => { setCount(count + 1) }> { count } </div>
<div onClick={() => { setCount(count => count + 1) }> { count } </div>
useEffect
相当于类组件的大部分生命周期函数,初始调用一次,第二个参数是一个数组,只有当数组中的元素发生变化的时候才能出发,一般数组中的元素都是基本数据类型或者不是太复杂的数据,可以使用多个
useEffect(() => {
...
return () => {
// return 里面的函数相当于componentWillUnmount生命周期函数,通常做定时器的销毁或者其他一些操作
}
}, [count, name]) // 第二个参数中任意一项发生变化都会触发,支持表达式的写法,比如count > 5 ? true : count,代表count > 5的时候会是一个常量5,不会再触发useEffect函数
注:有一个类似hooks叫useLayoutEffect,写法和用法和useEffect相同,但是有更高的优先级,执行更快,但是一般使用useEffect
createContext和useContext
import { createContext, useContext } from 'react';
const content = createContext();
const { Provider } = content;
function A() {
return <div>
<B></B>
</div>
}
function B() {
const value2 = useContext(content); // 只要通过useContext(content)调用,被Provinder
return <div>
<div> { value2.name } </div>
</div>
}
function App() {
return (
<Provider value={{name: '张三'}}> // value字段可以向下传递
<A></A>
</Provider>
);
}
ref
function App() {
const inp = useRef()
return (
<div>
<input ref={inp} /> // 也可以ref={(refDom
) => { }}
<button
onClick={() => {
inp.current.value = Date.now()
}}
> 点击获取当前时间戳 </button>
</div>
)
}
// 如果子组件是函数式组件的话,通常使用forwardRef
import { forwardRef, useRef } from 'react';
function A(props, ref) {
return <input ref={ref}/>
}
const AFef = forwardRef(A); // 可以使用ref,为函数式组件的第二个参数
function App() {
const inp = useRef();
return (
<div>
<AFef ref={inp} />
<button
onClick={() => {
inp.current.value = Date.now()
}}
> 点击获取当前时间戳 </button>
</div>
)
}
// 但是上面这种写法会将整个子组件的ref元素全部导出,这是我们不需要的,我们需要的仅仅是对ref元素进行一些操作,这个时候就要用到useImperativeHandle了
import { useImperativeHandle, useRef, forwardRef } from 'react';
function A(props, ref) {
let inpRef = useRef()
useImperativeHandle(ref, () => ({
focus: () => {
inpRef.current.focus();
},
getData: () => {
inpRef.current.value = 'hello world'
}
}), [])
return <input ref={inpRef}/>
}
const AFef = forwardRef(A);
function App() {
const inp = useRef();
return (
<div>
<AFef ref={inp} />
<button
onClick={() => {
console.log('inp', inp)
}}
> 点击获取当前时间戳 </button>
</div>
)
}
通过打印inp,可以得到
这个时候就可以进行自己想要操作的事情了
useCallback
function App() {
let [count, setCount] = useState(0);
const clickFunc = useCallback(() => {
setCount(count + 1);
}, [count]) // 当count发生变化的时候才会刷新值
return (
<div>
{ count }
<button onClick={ clickFunc }> 点击 </button>
</div>
)
}
useMemo
为防止组件频繁刷新,useMemo第二个参数为数组,只有数组中的元素发生变化的时候才刷新
const A = useMemo(() => {
}, [count]) //只有count发生变化的时候才刷新
function App() {
return <A></A>
}
useReducer
在某些场景下,useReducer 会比 useState 更适用,例如 state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 等。
import { useReducer } from 'react';
const initState = {
count: 0
}
const reducer = (state, action) => {
const { type, payload } = action;
console.log('type', type)
switch(type) {
case 'increment':
return { ...state, count: state.count + payload.step }
case 'decrement':
return { ...state, count: state.count - payload.step }
default:
break;
}
}
function App() {
const [state, dispatch] = useReducer(reducer, initState) // 接受两个参数,第一个是处理函数,第二个是初始数据,返回state数据和dispatch函数
return <>
<div>{ state.count } </div>
<button onClick={() => { dispatch({ type: 'increment', payload: { step: 2 } }) }}> + </button>
<button onClick={() => { dispatch({ type: 'decrement', payload: { step: 2 } }) }}> - </button>
</>
}