这半年来重度使用了react,有的项目中完全使用了hooks,还记得使用react从刚开始的懵懵懂懂,跌跌撞撞,到现在的游刃有余,一路走来真是觉得万分煎熬啊,因为我以前工作中更多的是用vue,有vue的使用经验,所以拾起react也没那么难,但也没并不轻松。
工作中,有的项目react版本较低,只能使用class组件,当我习惯了写hooks,切换到使用class组件的项目中时,总是觉得很难受,感觉写起来很繁琐,啰嗦,因为总是要写this,this,this,this.state,this.props,还有很多个生命周期方法,还有让我很痛苦的是当我变更状态使用setState时,state是个对象的时候,我还得复制一份这个对象,生成新的对象,再setState。
现在,只要是在支持hooks的项目中,我都用hooks来写组件,它解决了我以上的所有痛点,让开发组件的体验焕然一新,在一些简单的项目中我发现竟然用两个hooks api就完全足够了,比如useState和useEffect,真是太神奇了!
好了,现在进入主题吧。
useState
一个鲜活的应用程序都有大量状态,内容无法变化的话,我们是无法使用的,所以useState在react中是非常重要的。
更多介绍可以看官方文档哈,下面来看看它的一个有趣应用。
实现组件的强制刷新。
function App() {
//使用useForceUpdate
const forceUpdate = useForceUpdate()
return (
<div>
<div>Time: {Date.now()}</div>
<button onClick={forceUpdate}>强制更新</button>
</div>
)
}
const useForceUpdate = () => {
const [, setState] = useState({})
return () => setState({})
}
我们可以发现每次点击强制更新button的时候,time的内容也跟着变化。
useEffect
每当组件渲染完成时,会调用这个effect,那么我们可以在这里做数据获取、操作DOM和BOM等工作,你还可以返回一个函数,这个函数会在组件卸载前被调用。
function App() {
const [count, setCount] = useState(0)
const handleClick = () => {
setCount(count + 1)
}
useEffect(() => {
console.log('组件已挂载')
return () => {
//可以在这做一些组件的清除工作
console.log('组件已卸载')
}
})
return (
<div>
<button onClick={handleClick}>Increment</button>
</div>
)
}
//首次渲染和点击2次Increment按钮,控制台依次打印:
//"组件已挂载"
//"组件已卸载"
//"组件已挂载"
//"组件已卸载"
//"组件已挂载"
由此发现,组件挂载完成时,会调用useEffect,当点击Increment按钮,组件的state发生变更时,组件需要重新渲染,然后组件经历了被卸载和被挂载的过程。
useEffect如何只在组件挂载时执行
很简单,useEffect的第2个参数是个依赖数组,当我们指定了依赖数组,就只会在依赖发生改变时执行useEffect,它还可以接收一个空数组,这样就只会在组件挂载时执行了。
useEffect(() => {
console.log('管你state如何变,我永远只会在组件挂载时执行一次')
}, [])
useRef和useEffect结合忽略首次渲染(执行)
useRef不仅仅可以获取dom,它还可以存储任何值,而不随状态改变导致组件重新渲染而改变。
const isMounted = useRef(false)
useEffect(() => {
if (!isMounted.current) {
isMounted.current = true
} else {
//do something
}
})
useCallback
useCallback 返回一个经过缓存的回调函数 , 它接收2个参数,一个是回调函数,一个是依赖数据,当依赖项变化的时候,才会重新更新回调函数。它主要是用来做性能优化的。
比如下面的例子,假如我们的useForceUpdate经常被使用的话,可以使用useCallback包裹,这样每次调用和组件重渲染使用的都是缓存过的函数,减少重新初始化函数的性能损耗。
function App() {
const forceUpdate = useForceUpdate()
return (
<div>
<div>time:{Date.now()}</div>
<button onClick={forceUpdate}>强制更新</button>
</div>
)
}
const useForceUpdate = () => {
const [, setState] = useState({})
return useCallback(() => setState({}), [])
}
useMemo
useMemo 可以缓存一个值,一般是用来做性能优化的,它接受2个参数,一个是返回计算值的回调函数,一个是依赖数组,当依赖发生变化时,才会重新更新函数,下面来看代码掌握它。
function App() {
const forceUpdate = useForceUpdate()
const count = useMemo(() => {
console.log('called')
return 1 + 1
}, [])
return (
<>
<div>count:{count}</div>
<button onClick={forceUpdate}>强制更新</button>
</>
)
}
运行程序首次打印called,当我们点击强制更新button时,控制台没有再次打印called,由此发现,useMemo具有缓存计算的能力,所以在一些耗时的计算中可以使用它。
useImperativeHandle 和 forwardRef结合
父组件通过ref访问子组件的时候,可以在子组件中使用useImperativeHandle向父组件暴露接口(实例方法),useImperativeHandle通常和forwardRef结合使用。
function App() {
const inputModal = useRef()
const showInputModel = () => {
inputModal.current.show()
}
const hideInputModel = () => {
inputModal.current.hide()
}
return (
<div>
<button onClick={showInputModel}>show modal</button>
<button onClick={hideInputModel}>hide modal</button>
<InputModal ref={inputModal} />
</div>
)
}
const InputModal = forwardRef((props, ref) => {
const inputRef = useRef()
const [show, setShow] = useState(false)
useImperativeHandle(ref, () => ({
show: () => setShow(true),
hide: () => setShow(false),
}))
useEffect(() => {
if (show) inputRef.current.focus()
})
return (
show && (
<div>
<form>
<div>
<label>What's your name?</label>
<input ref={inputRef} />
</div>
</form>
</div>
)
)
})
代码中,使用了useImperativeHandle向父组件暴露show和hide方法,这何尝不是实现控制model显示和隐藏的方法?
useLayoutEffect
useLayoutEffect 和 useEffect 功能相同,但不同的地方在于渲染机制,useLayoutEffect会跟dom同步渲染,在里面更新dom布局会同步触发重渲染。
function App() {
const app = useRef()
// useEffect(() => {
// app.current.style.left = '100px'
// })
useLayoutEffect(() => {
app.current.style.left = '100px'
})
return (
<div
ref={app}
style={{
position: 'absolute',
width: '80px',
height: '80px',
backgroundColor: 'tomato',
}}
/>
)
}
运行上面代码,不断刷新浏览器你可以发现useEffect里的色块你能看到它的布局过程,但在useLayoutEffect中是看不到的,当你遇到这种情况的时候,可以尝试用它来解决。
最后:
上面是我在项目中使用hooks的一些发现和经验,分享给大家,hooks的开发体验非常棒,使用起来简单,轻松,几个hooks即可满足开发需求,极大的降低了开发者的学习成本,大大的提高了开发效率。
除去吃喝拉撒睡,可见我使用react和hooks的时间也不算太长,如有错误的地方,欢迎留言与我交流。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!