一、创建
const App = (props)=>{
return <div>{props.message}</div>
}
函数组件的问题:
- 没有 state ---- React v16.8.0 推出 Hooks API,用
useState解决 - 没有生命周期 ---- Hooks API,用
useEffect解决
二、state
使用useState
const App = props => {
const [n, setN] = React.useState(0)
return //...
}
三、生命周期
使用useEffect
useEffect接收两个参数:useEffect(fn, arr)
1、模拟 componentDidMount
useEffect(fn, []) //第二个参数为空数组,仅在第一次渲染后调用fn
2、模拟 componentDidUpdate
useEffect(fn, [n, m]) //第一次渲染,以及数组内的数据变化,调用fn
useEffect(fn) //第一次渲染,以及任何数据变化均会调用fn
问题:这样写第一次渲染时也会调用fn,如何实现仅在数据更新后才调用?
解决:在fn中加入条件判断,用一个变量记录n更新的次数,次数>1,再执行操作
const [nUpdateCount, setNUpdateCount] = useState(0)
useEffect(()=>{
setNUpdateCount(x=>x+1)
}, [n])
useEffect(()=>{
if(nUpdateCount > 1){
console.log('n变了')
}
}, [nUpdateCount])
优化:自定义一个Hook,将上述代码封装为一个useUpdate函数,useUpdate(fn, n)表示仅当n更新时调用fn
const useUpdate = (fn, dep)=>{
const [count, setCount] = useState(0)
useEffect(()=>{
setCount(x => x+1)
}, [dep])
useEffect(()=>{
if(count>1){
fn()
}
}, [count, fn])
}
3、模拟 componentWillUnmount
useEffect(fn),fn返回的函数会在组件销毁时执行,即:
useEffect(()=>{
return ()=>{/* ... */}
})
【例】
模拟一个组件被销毁的场景,点击按钮销毁子组件Child:
const App = props => {
const [childVisible, setChildVisible] = React.useState(true)
const show = ()=>{setChildVisible(true)}
const hide = ()=>{setChildVisible(false)}
return (
<div>
{childVisible?
<button onClick={hide}>隐藏</button>:
<button onClick={show}>显示</button>}
{childVisible?<Child />:null}
</div>
)
}
const Child = props => {
useEffect(()=>{
return ()=>{console.log('child销毁了')}
})
return (
<div>我是child</div>
)
}
4、模拟 shouldComponentUpdate
用React.memo和useMemo,详见后续