react中使用hooks编程有什么优势
dearweb 发布:2021-09-26 11:23:36阅读:相信接触react比较早的朋友一定是使用的class类进行编程,自16.8.0开始。react以及发布了hooks,也就是说16.8.0之后你可以使用hooks方式进行编程,hooks相比于类组件式编程有什么优势呢?下面主要介绍一下hooks编程方式,完了之后,也许你就知道哪一种编程方式更属于你了。
函数式和类组件的对比
首先对于react编程中类组件和纯函数组件的区别还是比较大的,纯函数组件有着类组件不具备的多种特点,简单列举几条。
纯函数组件没有状态 纯函数组件没有生命周期 纯函数组件没有this 只能是纯函数
上面的几点缺陷注定函数组件,只能做UI展示的功能,涉及到状态的管理与切换,我们不得不用类组件或者redux,说完函数式组件,我们来看看类组件,类组件的也是有缺点的,比如,遇到简单的页面,你的代码会显得很重,并且每创建一个类组件,都要去继承一个React实例,这就导致了类组件天生就有以下几个缺点。
大型组件很难拆分和重构,也很难测试。 业务逻辑分散在组件的各个方法之中,导致重复逻辑或关联逻辑。 组件类引入了复杂的编程模式,比如 render props 和高阶组件。
举个计数器的例子来对比一下
import React from 'react'class AddCount extends React.PureComponent { constructor(props){ super(props) this.state={ count: 0 } } addcount = () => { let newCount = this.state.count this.setState({ count: newCount +=1 }) } render(){ return ( <> <p>{this.state.count}</p> <button onClick={this.addcount}>count++</button> </> ) }}export default AddCount
上面代码一写完相信不少小伙伴就可以看到,代码确实很重。 为了解决这种,类组件功能齐全却很重,纯函数很轻便却有上文几点重大限制,React团队设计了React Hooks,React Hooks就是加强版的函数组件,我们可以完全不使用 class,就能写出一个全功能的组件。
了解一下hooks
'Hooks'的单词意思为“钩子”。 React Hooks 的意思是,组件尽量写成纯函数,如果需要外部功能和副作用,就用钩子把外部代码"钩"进来。而React Hooks 就是我们所说的“钩子”。 那么Hooks要怎么用呢?“你需要写什么功能,就用什么钩子”。对于常见的功能,React为我们提供了一些常用的钩子,当然有特殊需要,我们也可以写自己的钩子。下面是React为我们提供的默认的四种最常用钩子。
useState() // 状态钩子 useContext() // 共享状态钩子 useReducer() // Action钩子 useEffect() // 副作用钩子
不同的钩子为函数引入不同的外部功能,我们发现上面四种钩子都带有use前缀,React约定,钩子一律使用 use前缀命名。所以,你自己定义的钩子都要命名为useXXX。
hooks的使用方法介绍
userState():状态钩子
我们知道,纯函数组件没有状态,useState()用于为函数组件引入状态。
下面我们使用Hooks重写上面的计数器。
import React, {useState} from 'react'const AddCount = () => { const [ count, setCount ] = useState(0) const addcount = () => { let newCount = count setCount(newCount+=1) } return ( <> <p>{count}</p> <button onClick={addcount}>count++</button> </> )}export default AddCount
通过上面的代码,我们实现了一个功能完全一样的计数器,代码看起来更加的轻便简洁,没有了继承,没有了渲染逻辑,没有了生命周期等。这就是hooks存在的意义。
在useState()中,它接受状态的初始值作为参数,即上例中计数的初始值,它返回一个数组,其中数组第一项为一个变量,指向状态的当前值。类似this.state,第二项是一个函数,用来更新状态,类似setState。该函数的命名,我们约定为set前缀加状态的变量名。
useContext():共享状态钩子
该钩子的作用是,在组件之间共享状态。关于Context这里不再赘述,其作用就是可以做状态的分发,在React16.X以后支持,避免了react逐层通过Props传递数据。
下面是一个例子,现在假设有A组件和B组件需要共享一个状态。
import React,{ useContext } from 'react' const Ceshi = () => { const AppContext = React.createContext({}) const A =() => { const { name } = useContext(AppContext) return ( <p>我是A组件的名字{name}<span>我是A的子组件{name}</span></p> )} const B =() => { const { name } = useContext(AppContext) return ( <p>我是B组件的名字{name}</p> )} return ( <AppContext.Provider value={{name: 'hook测试'}}> <A/> <B/> </AppContext.Provider> )}export default Ceshi
如果你看到了上面的图片结果,则证明通过hooks做状态的共享。
useReducer():Action钩子
我们知道,在使用React的过程中,如遇到状态管理,我们一般会用到Redux,而React本身是不提供状态管理的。而useReducer()为我们提供了状态管理。首先,关于redux我们都知道,其原理是我们通过用户在页面中发起action,从而通过reducer方法来改变state,从而实现页面和状态的通信。而Reducer的形式是(state, action) => newstate。类似,我们的useReducer()是这样的。
const [state, dispatch] = useReducer(reducer, initialState)
它接受reducer函数和状态的初始值作为参数,返回一个数组,其中第一项为当前的状态值,第二项为发送action的dispatch函数。下面我们依然用来实现一个计数器。
和redux一样,我们是需要通过页面组件发起action来调用reducer方法,从而改变状态,达到改变页面UI的这样一个过程。所以我们会先写一个Reducer函数,然后通过useReducer()返回给我们的state和dispatch来驱动这个数据流。思路就是这样,下面我们上代码。
import React,{useReducer} from 'react' const AddCount = () => { const reducer = (state, action) => { if(action.type === ''add){ return { ...state, count: state.count +1, } }else { return state } } const addcount = () => { dispatch({ type: 'add' }) } const [state, dispatch] = useReducer(reducer, {count: 0}) return ( <> <p>{state.count}</p> <button onClick={addcount}>count++</button> </> ) } export default AddCount
通过代码我们看到了,我们使用useReducer()代替了Redux的功能,但useReducer无法为我们提供中间件等功能,加入你有这些需求,还是需要用到redux。
useEffect():副作用钩子
熟悉redux-saga的同学一定对Effect不陌生,它可以用来更好的处理副作用,如异步请求等,我们的useEffect()也是为函数组件提供了处理副作用的钩子。依然我们会把请求房子componentDidMount里面,在函数组件中我们可以使用useEffect()。其具体用法如下
useEffect(() => {},[array])
useEffect()接受两个参数,第一个参数是你要进行的异步操作,第二个参数是一个数组,用来给出Effect的依赖项。只要这个数组发生变化,useEffect()就会执行。当第二项省略不填时,useEffect()会在每次组件渲染时执行。这一点类似于类组件的componentDidMount。下面我们通过代码模拟一个异步加载数据。
import React, { useState, useEffect } from 'react' const AsyncPage = () => { const [loading, setLoading] = useState(true) useEffect(() => { setTimeout(()=> { setLoading(false) },5000) }) return ( loading ? <p>Loading...</p>: <p>异步请求完成</p>) } export default AsyncPage
上面的代码实现了一个异步加载,下面我们再做一个useEffect()依赖第二项数组变化的例子。
import React, { useState, useEffect } from 'react' const AsyncPage = ({name}) => { const [loading, setLoading] = useState(true) const [person, setPerson] = useState({}) useEffect(() => { setLoading(true) setTimeout(()=> { setLoading(false) setPerson({name}) },2000) },[name]) return ( <> {loading?<p>Loading...</p>:<p>{person.name}</p>} </> )} const PersonPage = () =>{ const [state, setState] = useState('') const changeName = (name) => { setState(name) } return ( <> <AsyncPage name={state}/> <button onClick={() => {changeName('名字1')}}>名字1</button> <button onClick={() => {changeName('名字2')}}>名字2</button> </> )} export default PersonPage
上面代码中,通过改变传给AsyncPage的props,从而调用useEffect()。
如何创建自己的Hooks
以上我们介绍了四种最常用的react提供给我们的默认React Hooks,有时候我们需要创建我们自己想要的Hooks,来满足更便捷的开发,在小编看来,无非就是根据业务场景对以上四种Hooks进行组装,从而得到满足自己需求的钩子。
比如,我们要将我们上面的代码功能封装成Hooks,代码如下
import React, { useState, useEffect } from 'react' const usePerson = (name) => { const [loading, setLoading] = useState(true) const [person, setPerson] = useState({}) useEffect(() => { setLoading(true) setTimeout(()=> { setLoading(false) setPerson({name}) },2000) },[name]) return [loading,person]} const AsyncPage = ({name}) => { const [loading, person] = usePerson(name) return ( <> {loading?<p>Loading...</p>:<p>{person.name}</p>} </> ) } const PersonPage = () =>{ const [state, setState]=useState('') const changeName = (name) => { setState(name) } return ( <> <AsyncPage name={state}/> <button onClick={() => {changeName('名字1')}}>名字1</button> <button onClick={() => {changeName('名字2')}}>名字2</button> </> )} export default PersonPage
上面代码中,我们将之前的例子封装成了自己的Hooks,便于共享。其中,我们定义usePerson()为我们的自定义Hooks,它接受一个字符串,返回一个数组,数组中包括两个数据的状态,之后我们在使用usePerson()时,会根据我们传入的参数不同而返回不同的状态,然后很简便的应用于我们的页面中。
至此,文章关于React Hooks的讲解结束,它为我们带来了React翻天覆地的变化,也让我们感受到了React的未来,不过,假如你不会Hooks也是没有关系的。因为官方是这么介绍hooks的:
- 完全可选的。 你无需重写任何已有代码就可以在一些组件中尝试 Hook。但是如果你不想,你不必现在就去学习或使用 Hook。
- 100% 向后兼容的。 Hook 不包含任何破坏性改动。
- 现在可用。 Hook 已发布于 v16.8.0。
- 没有计划从 React 中移除 class。
- Hook 不会影响你对 React 概念的理解。 恰恰相反,Hook 为已知的 React 概念提供了更直接的 API:props, state,context,refs 以及生命周期。
看到这里你是不是感觉很爽。hooks还是希望大家多学学的,毕竟可以看到以后会有越来越多的人开始使用hooks写react。
小礼物走一波,支持作者
赏还没有人赞赏,支持一波吧