为什么是hooks
钩子
useState
- 用于定义组件的
state,对标到类组件中的this.state的功能
function Com() {
const [state, setState] = useState(0) // 0是默认值
}
useEffect
- 通过
依赖触发的钩子函数,常用于模拟组件的生命周期:componentDidMount、componentDidUpdate、componentWillUnmount
useEffect(
()=>{
console.info("生命周期1")
const timer = setTimeout(()=>{},1000)
return ()=>{
console.info("生命周期2")
clearTimerout(timer)
}
},
[n]
)
上面例子中
- 组件第一次加载的时候,触发了生命周期1,触发的是componentDidMount
- 当依赖n发生变化的时候,触发了生命周期1,触发的是componentDidUpdate
- 当组件卸载时,触发了生命周期2,触发的是componentWillUnmount
useLayoutEffect
- DOM更新的同步钩子,用法和useEffect类似,只是执行时间不同
useEffect:属于异步执行,并不会等待DOM真正渲染后执行useLayoutEffect:会真正渲染后才触发,可以获取更新后的state
useReducer
- 类似于
Redux思想的实现,单其并不足以替代Redux,可以理解成一个组件内部的redux - 并
不是持久化存储,会随着组件被销毁而销毁 - 属于
组件内部,组件之间无法共享数据
// 初始值
const initialState = {count: 0};
// 数据变更方法
function reducer(state, action) {
const { payload } = action;
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default: throw new Error();
}
}
// 定义
const [state, dispatch] = useReducer(reducer, initState);
// 分发
dispatch({type: 'increment', payload: "传递什么信息呢?"})}
useContext
- 提供
context对象
var defaultValue = {}
var context = React.useContext(defaultValue);
<context.Provider>
<context.Consumer>
<context.Consumber>
</context.Provider>
useCallback
缓存回调函数,避免传入的回调每次都是新的函数实例而导致依赖组件重新渲染- 返回值:memoized
函数
const memoizedCallback = useCallback(() => {
// 这里做什么
}, [a])
当a变化的时候,才会重新生成新的函数
useMemo
- 返回值: memoized 值
- 用于缓存传入的props,避免依赖的组件每次都重新渲染.可以实现
值的缓存
// 没有使用useMemo
const data = {
name,
}
上面看着好像没有什么问题,但是你要知道,每次函数钩子,执行update的时候,data都会被赋值一个新的对象,data就不是原来的对象了。这个就会不停的触发更新
// 使用useMemo
const data = useMemo(function useMemoCallback(){
return {
name,
}
}, [name])
上面的例子,如果name变化,useMemoCallback函数,会执行,并把返回值赋值给data。当name没有变化的情况下,data的值始终是一个对象地址
useMemo模拟memo
如题,如何模拟呢?如果你不知道memo的作用,先看下面的memo讲解
useMemo(() => {
return <Card1 name={name}/>
}, [name])
如果name没有变化,useMemo返回的卡片组件,就不会重复render,实现了一个PureComponent的方法
useRef
- 返回值:一个可变的ref对象
- 用来存储一个常量
方法一:保存常量
var refValue = useRef(null)
console.info(refValue.current)
refValue.current = 112;
方法二:引用dom
function Com() {
var inputRef = React.useRef();
return <input ref={inputRef} />
}
通常结合forwordRef使用
function Func(props, ref) {
const inputRef = React.useRef();
useimperativehandle(ref, () => {
// 扩展了Func这个函数组件的ref方法,新增了一个focus
focus: inputRef.current.focus();
})
return <input ref={inputRef}/>
}
const MyInput = React.forwardRef(Func)
未来使用MyInput时,可以通过myinputRef.current.focus来触发Func组件中的input框的focues事件
其他
Q & A
useState没有回调函数,如何处理
- 在class组件中this.setState方法,接收第二个回调参数,在re-render后执行,但是这样的情况下,更推荐
comonentDiUpdate中实现回调函数的执行
class Com extends React.Component {
state = {
count: 1,
}
componentDidMount() {
this.setState({ count: 3 }, () => {
console.info(this.state.count)
})
}
componentDidUpdate() {
console.info(this.state.count)
}
render() {
return null;
}
}
- 函数组件可以使用
useEffect或useLayoutEffect模拟实现componentDidUpdate
function Com() {
const [count, updateCount] = React.useState(0);
useEffect(() => {
updateCount(1)
}, [])
useEffect(() => {
console.info(count)
}, [count])
}