HOC、Render props VS Hooks
共 5942字,需浏览 12分钟
· 2021-01-13
工作中虽然在用react技术栈做开发,但react hooks 还没有实际用到,一直都在用redux。毕竟都2021了,如果还不会hooks真有点说不过去了,会怀疑我还是前端吗?
所以最近打算学习下 hooks。今天就记录一些浅显的理解,通过具体示例来感受下hooks的魅力。
个人理解
react hooks的作用:实现状态处理逻辑的封装,他是一个全新的API,彻底解决之前类组件中『状态处理逻辑』很难复用的问题,其实和render props
和hoc
的功效是一样的。只不过hooks更彻底,更好用。
感受hooks的魅力
下面通过具体的代码示例来进行分析和理解、感受hooks
的作用和魅力。
比如我们现在有个需求要实现两种产品列表,用于前后台展示。
前台产品列表
后台产品列表
常规的,类组件处理方式
看到上面的需求后,常规做法是会分别写两个组件,然后使用统一的产品列表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 "procardlist">前台产品列表
{this.state.proList.map(item =>
产品名称:{item.title}
价格:{item.price}
)}
}
}
后台产品列表组件
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 "procardlist">管理员看到的产品列表
产品名称 产品简介 价格
{this.state.proList.map(item =>
{item.title}
{item.des}
{item.price}
)}
}
}
我们发现上面两个组件的状态处理逻辑是完全一致的,唯一不同的地方就是render部分。所以我们为了减少重复代码,使状态处理逻辑能够复用,会提取出两个组件无状态list组件,只用于渲染产品列表,且只接受一个props属性-proList(产品列表数据)。
前台产品列表组件
既然是无状态组件,直接使用函数组件即可
// FrontProductList.jsx
import React from 'react'
export default ({proList=[]}) => {
return "procardlist">前台产品列表
{proList.map(item =>
产品名称:{item.title}
价格:{item.price}
)}
}
后台产品列表组件
//AdminProductList.jsx
import React from 'react'
import { getProductList } from '../../module/product'
//产品管理后台list
export default ({proList=[]})=> {
return "procardlist">后台产品列表
产品名称 产品简介 价格
{proList && proList.map(item =>
{item.title}
{item.des}
)}
}
那现在我们的状态处理组件就变成下面这样了。
//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 {
this.props.render(this.state.proList)}
}
}
调用方式
前台产品列表
}/>
后台产品列表
}/>
使用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
}
}
}
调用方式
前台产品列表
......
const FrontProductList = ProductData(FrontProductList)
......
render(){
return
}
后台产品列表
......
const AdminProductList = ProductData(AdminProductList)
.....
render(){
return
}
使用hooks
上面我们使用render props
和HOC
这两种模式确实达到了状态处理逻辑复用的目的,那有没有更好的方式呢?
是时候表演真正的技术了。------ 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 "procardlist">管理员看到的产品列表 - hooks
产品名称 产品简介
{proList.map(item =>
{item.title}
{item.des}
)}
}
继续我们的菜, 在最开始我们提取出来的两个产品列表组件依然可用。
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
}
写到这里,不得不说hooks是真的香。
之前的逻辑复用只能是通过组件的方式来复用,代码多,上手成本也高。
而hooks直接突破,可以将状态处理逻辑直接封装成函数来进行调用。
小结
本文内容比较浅,所以咱们就浅显的看,其实react hooks就是几个api,这几个api调用都非常简单(只谈使用,原理后面再说),但可以实现完全使用函数组件达到原来类组件的效果,而且代码量少,不需要关心this,没有生命周期,最主要的是可以将状态处理逻辑封装成高度复用的函数,这是突破也是颠覆,更承认这是react的未来。
也许你已经习惯了类组件的开发方式,但就仅仅这种颠覆的逻辑复用方式,hooks就值得一试。
后面会用更多的代码示例来学习react hooks。
点个『在看』支持下