HOC、Render props VS Hooks

简介: 工作中虽然在用react技术栈做开发,但react hooks 还没有实际用到,一直都在用redux。毕竟都2021了,如果还不会hooks真有点说不过去了,会怀疑我还是前端吗?所以最近打算学习下 hooks。今天就记录一些浅显的理解,通过具体示例来感受下hooks的魅力。

工作中虽然在用react技术栈做开发,但react hooks 还没有实际用到,一直都在用redux。毕竟都2021了,如果还不会hooks真有点说不过去了,会怀疑我还是前端吗?

所以最近打算学习下 hooks。今天就记录一些浅显的理解,通过具体示例来感受下hooks的魅力。

个人理解


react hooks的作用:实现状态处理逻辑的封装,他是一个全新的API,彻底解决之前类组件中『状态处理逻辑』很难复用的问题,其实和render propshoc的功效是一样的。只不过hooks更彻底,更好用。

感受hooks的魅力


下面通过具体的代码示例来进行分析和理解、感受hooks的作用和魅力。

比如我们现在有个需求要实现两种产品列表,用于前后台展示。

前台产品列表

781edf1833dabdc72316bccf1de8bdc9_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

后台产品列表

b5d4b3953219933820d2b02b3a22ed53_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


常规的,类组件处理方式


看到上面的需求后,常规做法是会分别写两个组件,然后使用统一的产品列表api请求方法获取数据,然后处理状态。

前台产品列表组件

import React from 'react'
//产品列表api获取方法
import { getProductList } from '../../module/product'
export default class FrontProductList extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      proList: []
    }
  }
  componentDidMount() {
    getProductList().then(list => {
      this.setState({
        proList: list
      })
    })
  }
  render() {
    return <div className="procardlist"><h2>前台产品列表</h2>
      {this.state.proList.map(item => <div key={item.id}>
        <p>产品名称:{item.title}</p>
        <p><img src={item.pic}/></p>
        <p>价格:{item.price}</p>
      </div>)}
    </div>
  }
}

后台产品列表组件

import React from 'react'
import { getProductList } from '../../module/product'
//产品管理后台list
export default class AdminProductList extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      proList: []
    }
  }
  componentDidMount() {
    getProductList().then(list => {
      this.setState({
        proList: list
      })
    })
  }
  render() {
    return <div className="procardlist"><h2>管理员看到的产品列表</h2>
      <table>
        <tr>
          <td>产品名称</td>  <td>产品简介</td> <td>价格</td>
        </tr>
        {this.state.proList.map(item => <tr>
          <td>
            {item.title}
          </td>
          <td>
            {item.des}
          </td>
          <td>
            {item.price}
          </td>
        </tr>)}
      </table>
    </div>
  }
}

我们发现上面两个组件的状态处理逻辑是完全一致的,唯一不同的地方就是render部分。所以我们为了减少重复代码,使状态处理逻辑能够复用,会提取出两个组件无状态list组件,只用于渲染产品列表,且只接受一个props属性-proList(产品列表数据)。

前台产品列表组件

既然是无状态组件,直接使用函数组件即可

// FrontProductList.jsx
import React from 'react'
export default ({proList=[]}) => {
  return <div className="procardlist"><h2>前台产品列表</h2>
    {proList.map(item => <div key={item.id}>
      <p>产品名称:{item.title}</p> <p>价格:{item.price}</p>
    </div>)}
  </div>
}

后台产品列表组件

//AdminProductList.jsx
import React from 'react'
import { getProductList } from '../../module/product'
//产品管理后台list
export default ({proList=[]})=> {
    return <div className="procardlist"><h2>后台产品列表</h2>
      <table>
        <tr>
          <td>产品名称</td>  <td>产品简介</td> <td>价格</td>
        </tr>
        {proList && proList.map(item => <tr>
          <td>
            {item.title}
          </td>
          <td>
            {item.des}
          </td>
        </tr>)}
      </table>
    </div>
}

那现在我们的状态处理组件就变成下面这样了。

//ProductData.jsx
import React from 'react'
import { getProductList } from '../../module/product'
export default class ProductData extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      proList: []
    }
  }
  componentDidMount() {
    getProductList().then(list => {
      this.setState({
        proList: list
      })
    })
  }
  //但我应该渲染哪个组件呢
  render() {
    return ?????
  }
}

但上面代码并没有写完,因为我们发现在render方法里我们不知道该渲染哪个列表组件?

使用render props


render props并不是什么新特性,只是一种函数调用模式而已,它可以把特定行为或功能封装成一个组件,提供给其他组件使用让其他组件也拥有这样的能力。而上面的问题就可以通过render props来解决。

说白了就是回调方法。

function GetList(callback){
 const list = getProductList()
    const result = callback(list)
    return reuslt
}

那对应到组件的实现方式想必你已经想到了。

//ProductData.jsx
import React from 'react'
import { getProductList } from '../../module/product'
export default class ProductData extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      proList: []
    }
  }
  componentDidMount() {
    getProductList().then(list => {
      this.setState({
        proList: list
      })
    })
  }
  //通过回调的方式来拿到要渲染的组件,父组件内部完全不需要知道渲染的是什么组件
  render() {
  return <div>{
    this.props.render(this.state.proList)}</div>
  }
}

调用方式

前台产品列表

<ProductData render={result=><FrontProductList proList={result}/>}/>

后台产品列表

<ProductData render={result=><AdminProductList proList={result}/>}/>

使用HOC


对于状态逻辑处理的复用,除了render props能做到,HOC也能做到,只是实现方式不同。

高阶组件的定义就不多说了,直接上代码。

import React from 'react'
import { getProductList } from '../../module/product'
//WrapperdComponent就是我们要渲染的产品列表组件
export default (WrapperdComponent)=>{
//ProductData 就是具有状态处理能力的组件
  return class ProductData extends React.Component {
    constructor(props) {
      super(props)
      this.state = {
        proList: []
      }
    }
    componentDidMount() {
      getProductList().then(list => {
        this.setState({
          proList: list
        })
      })
    }
    render() {
    //最终在这里渲染我们的列表组件
     return <WrapperdComponent {...this.props} proList={this.state.proList}/>
    }
  }
}

调用方式

前台产品列表

......
  const FrontProductList = ProductData(FrontProductList)
  ......
  render(){
   return <FrontProductList/>
  }

后台产品列表

......
  const AdminProductList = ProductData(AdminProductList)
  .....
  render(){
   return <AdminProductList/>
  }

使用hooks


上面我们使用render propsHOC这两种模式确实达到了状态处理逻辑复用的目的,那有没有更好的方式呢?

是时候表演真正的技术了。------ hooks闪亮登场。

先熟悉下,看下基于hooks的常规处理方式

//ProductList.jsx
import React from 'react'
import { getProductList } from '../../module/product'
import {useState,useEffect} from 'react'
export default function ProductList(){
  //获得产品列表数据
  const [proList,setProductList] = useState([])
  useEffect(()=>{
    getProductList().then(list => {
      setProductList(list)
    })
  },[])
  return <div className="procardlist"><h2>管理员看到的产品列表 - hooks</h2>
  <table>
    <tr>
      <td>产品名称</td>  <td>产品简介</td>
    </tr>
    {proList.map(item => <tr key={item.id}>
      <td>
        {item.title}
      </td>
      <td>
        {item.des}
      </td>
    </tr>)}
  </table>
</div>
}

继续我们的菜, 在最开始我们提取出来的两个产品列表组件依然可用。

AdminProductList.jsx
FrontProductList.jsx

对于状态处理逻辑部分的复用方式,可以提取成自定义hooks

//useProductData.jsx
import React from 'react'
import { getProductList } from '../../module/product'
import {useState,useEffect} from 'react'
export default function useProductData(){
  const [proList,setProductList] = useState([])
  useEffect(()=>{
    getProductList().then(list => {
      setProductList(list)
    })
  },[])
  return proList //返回列表数据
}

调用方式

....
import useProductData from './components/ProductListHooks/useProductData'
import AdminProductList from './components/AdminProductList'
import FrontProductList from './components/FrontProductList'
function App(){
  const prolist = useProductData()
     return <AdminProductList proList={prolist}/>
}

写到这里,不得不说hooks是真的香。

之前的逻辑复用只能是通过组件的方式来复用,代码多,上手成本也高。

而hooks直接突破,可以将状态处理逻辑直接封装成函数来进行调用。

小结


本文内容比较浅,所以咱们就浅显的看,其实react hooks就是几个api,这几个api调用都非常简单(只谈使用,原理后面再说),但可以实现完全使用函数组件达到原来类组件的效果,而且代码量少,不需要关心this,没有生命周期,最主要的是可以将状态处理逻辑封装成高度复用的函数,这是突破也是颠覆,更承认这是react的未来。

也许你已经习惯了类组件的开发方式,但就仅仅这种颠覆的逻辑复用方式,hooks就值得一试。

后面会用更多的代码示例来学习react hooks。

目录
相关文章
|
7月前
|
缓存 JavaScript API
在vue中,computed 和 watch 的区别和运用的场景?
在vue中,computed 和 watch 的区别和运用的场景?
92 0
|
存储
React-组件Props和State的区别
React-组件Props和State的区别
60 0
|
1月前
|
存储 缓存 JavaScript
Vue 中 computed 和 watch 的差异
Vue 中的 `computed` 和 `watch` 都用于处理数据变化,但使用场景不同。`computed` 用于计算属性,依赖于其他数据自动更新;`watch` 用于监听数据变化,执行异步或复杂操作。
|
3月前
|
缓存
Vue3 的 computed 和 watch 函数有哪些不同?
Vue3 的 computed 和 watch 函数有哪些不同?
|
4月前
|
存储 前端开发
React 中的 state 和 props 有什么区别?
【8月更文挑战第31天】
53 0
|
缓存 JavaScript
Vue 中 computed 和 watch 的区别
Vue 中 computed 和 watch 的区别
94 0
|
7月前
|
前端开发
React中render Props模式
React中render Props模式
React中render Props模式
|
7月前
|
缓存 监控 JavaScript
Vue中的watch和computed有什么区别?
Vue中的watch和computed有什么区别?
50 0
|
7月前
|
缓存 JavaScript 前端开发
vue3 computed 和 watch 的差异
vue3 computed 和 watch 的差异
152 1
|
7月前
|
存储 前端开发
react中 state和props的区别
react中 state和props的区别
52 0