高阶组件
我们先来定个思路,1.什么是高阶组件?2.为什么用高阶组件?3.使用场景有哪些
什么是高阶组件
我们都知道高阶函数至少满足以下条件之一:
-
A函数的参数是一个或多个函数
-
A函数的返回值还是一个函数
我们亲切的称呼A函数是高阶函数
那什么是高阶组件呢?
高阶组件接收React组件作为参数经过一系列处理 包装成一个更加强大含有更多逻辑或者数据的一个新组件
既然能接收参数 还有返回值 妥妥的这个组件肯定是一个函数啊!!!
所以我们了解定义之后 就多了一个理解 高阶组件本质上就是一个函数 不是组件
-
高阶组件本质是一个函数
-
这个函数接收的参数是组件 返回值是一个组件
看完这些 额外补充概念例子:一个政治上的否定之否定定律!!! 和大学锤炼!!!
1,一个事物a1 经过自我否定 变成了一个新的事物a2
a2在a1的基础上变得更强了。
2,我们刚进大学首先身份是一个学生(A),经过学校的四年锤炼 出了校门瞬间也是一个学生(A`)
两者身份都是学生 但是学校已经把你封装成一个含有大学知识和生存能力的学生
所以 我们把上面的例子拆一下
a1是一个组件
经过 自我否定一下(自己定义的某个函数)
返回值是a2 新组件
学生A是一个组件
学校是一个函数
四年之后你还是你只不过比四年前的你更完美了。A`是新组件
为什么用高阶组件?
我们都知道在一个函数中处理的逻辑功能可能有很多组件都需要 我们的思路是啥?把这个功能函数封装一下 然后谁用谁引入这个函数就行了 不需要一个一个组件中先定义函数 然后写下逻辑 这不是容易造成代码的赋值冗余吗?
那如果组件除了逻辑还想要数据甚至是我还想要其他的React元素结构 那我们是不是就不能单纯把函数放进去封装;
第一:你要知道的是他的本质是一个函数 并且这个函数需要 参数 返回值
正好 参数是组件名 返回值还是组件名
这就是高阶组件
但是这个是废话 大白话就是 就是说你写好了两个组件 A,B 但是此时多了一个需求(随意) 并且A,B
这两个组件的增加逻辑功能 是一摸一样 就好比我写好其中一个另一个我可以粘贴复制一样
那么你想想 此时此刻我要是能把这些逻辑数据封起来 我给他这个组件 然后你给我一个带有这些重复逻辑的新组件,该多好
那么这个组件A就是平白无故多了一个父亲B ,, 我们只需要在父亲中写所有用我包装的孩子 数据要通过
props来传递
使用场景有哪些?
- 操纵props来传递数据
- 通过ref来访问组件实例对象
- 组件状态提升
- 用其他元素包裹着组件
操作props传递数据
想变强吗?那就找个爸爸把!!
我们在上面已经知道谁想变得更强就好比是给他外层找个爸爸 把复用的逻辑和数据放在爸爸身上你想要我通过props给你
例子:把姓名和一个方法放在爸爸身上 然后通过props传递给想变强的孩子 最后孩子可以访问数据和功能函数
在《需要包装组件》接收props前,高阶组件会先拦截到props,此时你可以对props执行增删改查 然后将处理好的props数据再传递给 《需要包装组件》
首先定义一个高阶组件 ----本质是一个函数
新建一个hoc.js文件
****第一种,什么也不做 你给我哪一个组件 我直接给你返回去那一个组件 我还是我不一样的烟火
export const withHoc=(WrappedComponent)=>{
//WrappedComponent 这个是形参自己起的组件名(大写) 也就是不论哪一个组件到我这里均是这个名字代替 被处理的组件
return function (props){
//这个返回值的函数记住这个可是组件---函数形式的组件 --函数式组件 他肯定要有返回值 React元素进行渲染的
return (
<WrappedComponent {...props}></WrappedComponent>
//这个返回值的组件才是爸爸 所有孩子想要的的数据和方法都在这组件中
/*
首先我们理解的是这个返回值才是真正人家组件需要的的爸爸组件
流程:一旦你被处理拥有了一个爸爸 那么以前人家传递给你的所有数据props
都会被该爸爸拦截下来 所以我们必须有一个动作就是把你原来的那些props的值原封不动的传回给你
至于你需要爸爸的数据那我重新按照父子通信交给你
*/
)
}
}
怎么使用? 创建一个组件名叫 MyComponent
第一步:先引入该函数
第二步:先定义函数组件名 然后用高阶组件处理一下再暴露出去
import React from 'react'
import withHoc from '../hoc'
// 第一步先定义组件
// 第二步 包装一下组件 类比connect不也是这样 数据通过props 来传给你
function MyComponent(props) {
console.log("props",props);
return (
<div>
我想变强
</div>
)
}
// 就是我的孩子外部平白无故多了一层父亲 让我拥有父亲的方法和数据 然后数据通过props 接收
export default withHoc(MyComponent)
为了确定是被拦截了 我们新建一个Home组件传递给MyConponent 看看如果MyComponent父亲不给你还能不能拿到
import React from 'react'
import MyComponent from '../Contral'
export default function Home() {
// 假如我们添加一个其他的给我的数据
return (
<MyComponent age={20} job="前端开发师"></MyComponent>
)
}
什么也没做? 控制台结果。。。首先是父亲拦截下来再给你
现在是拦截下来不传给你 很简单把上面那个渲染组件中的{...props}去掉就好了
***第二种 在爸爸这里建立数据和方法 传递给需要包装的组件
// 第二种 哪一个组件 不光想展示自己并且我还可以拿到在爸爸这里定义的数据和方法
const withHoc = (WrappedComponent)=>{
return function(props) {
// 一旦需要封装 所有给我的孩子发的数据都被我拦截
console.log("props我是WMyComponent的父亲接收的儿子数据",props);
const datalist={
name:"刘好杰"
}
// 返回一个组件
return (
// 第一种情况 什么也不做 你给我一个组件 我就把它直接给你渲染
<WrappedComponent {...datalist} {...props}></WrappedComponent>
)
}
}
控制台结果 注意看孩子组件的props含有的外来参数,name和handleName函数都是父亲的他自己本身是没有的
通过ref访问组件实例
ref获取被包装组件实例的引用,然后父亲高阶组件就可以直接操作孩子的属性或者方法 这个是类我们目前不说其实
就是和类中使用ref一样
组件状态的提升
有状态组件:就是用自身数据来搭建UI界面和实现功能 state
无状态组件:不用自身的全是外面给我的来搭建UI界面和实现功能 props
所以既然我们高阶组件是写数据和方法还能教给孩子 那么如果我把数据和方法都放在父亲高阶组件中通过props来得
到这不就是可以把有状态组件变成无状态组件
用其他元素包装组件
你仔细想想反正我都是返回的是个组件 自然我想怎么给他改变布局和样式都是可以的。那你就在返回的父亲组件
上随意些包裹组件的react元素
高阶组件的其他参数
高阶组件可以接收第二个参数自己指定需要的参数还可以是函数例如connext()(), 同时高阶组件还可以连续嵌套使用
要注意一下所谓的你定义的函数不是 是这个函数的返回组件才叫高阶组件