-
react 高阶组件 HOC 的个人理解和使用场景(易懂)
2020-03-23 13:30:30高阶组件就是接受一个组件作为参数并返回一个新组件(功能增强的组件)的函数。这里需要注意高阶组件是一个函数,并不是组件,这一点一定要注意。 使用场景 将几个功能相似的组件里面的方法和react特性(如生命周期...一句话介绍HOC
高阶组件就是接受一个组件作为参数并返回一个新组件(功能增强的组件)的函数。这里需要注意高阶组件是一个函数,并不是组件,这一点一定要注意。
使用场景
将几个功能相似的组件里面的方法和react特性(如生命周期里面的副作用)提取到HOC中,然后向HOC传入需要封装的组件。最后将公用的方法传给组件。
优势
使代码简洁优雅、代码量更少
代码示例:
高阶组件:`//定义高阶组件 //放在common公用方法里面 import React, { Component} from 'react'; export default (WrappedComponent) => { return class extends Component { constructor(props) { super(props) this.state = { //定义可复用的状态 count:1 } this.getCode = this.getCode.bind(this) } componentDidMount() { alert('111') } //定义可复用的方法 getCode(mobile) { // ... this.setState({count : mobile}) console.log(mobile) } postVcode(mobile) { // ... } render() { return ( <div> <WrappedComponent getCode={this.getCode} state={this.state} {...this.props}/> </div> ) } } } // 高阶组件就是把可复用的逻辑放在定义的高阶组件中,然后把需要调用高阶组件的组件作为参数传给高阶组件,然后在高阶组件中 // 实例化该组件,再把需要复用的方法和state传给次组件,然后在此组件中的props中就可以拿到高阶组件里定义的逻辑方法和state了
传入的组件:
import React, { Component} from 'react'; import HOC from './index' //高阶组件的使用 class Register extends Component{ render() { return ( <div> <button onClick={()=>{this.props.getCode('17682334636')}}>使用高阶组件里复用的方法</button> {this.props.state.count} </div> ) } } export default HOC(Register) //高阶组件其实就是将复用的方法传给组件,使代码简洁、代码量更少
-
详解react高阶组件(HOC)的用法以及它使用的场景
2021-04-17 10:22:55高阶组件听起来挺唬人的,只看名字恐怕不是那么容易明白究竟是何物,而且通常来讲高阶组件并不是组件,而是接受组件作为参数,并且返回组件的函数。早期利用 ES5 的 mixin 语法来做的事,基本都可以使用高阶组件代替...谈点:一篇面向初学者的 HOC 介绍。高阶组件听起来挺唬人的,只看名字恐怕不是那么容易明白究竟是何物,而且通常来讲高阶组件并不是组件,而是接受组件作为参数,并且返回组件的函数。早期利用 ES5 的 mixin 语法来做的事,基本都可以使用高阶组件代替,而且能做的还有更多。
前言
写这篇文章的起因是其他关于高阶组件(Higher-Order Components)的文章,包含官方文档,都令初学者感到相当困惑。我知道有高阶组件这样一个东西,但不知道它到底有什么用。所以,想通过一篇文章来对高阶组件有一个更好的理解。在此之前,我们需要先来讲一下 JavaScript 中的函数。
ES6 箭头函数简介
接下来将提供一些箭头函数的简单示例,如果之前没有使用过,可以认为它们与普通函数基本一致。下面的代码会展示箭头函数与普通函数的区别。function () {
return 42
}// 相当于:
() => 42// 相当于:
() => {
return 42
}function person(name) {
return { name: name }
}// 相当于:
(name) => {
return { name: name }
}
阅读 MDN 的箭头函数文档 了解更多信息。作为值的函数与部分调用
就像是数字、字符串、布尔值 一样,函数也是值,意味着可以像传递其他数据一样传递函数,可以将函数作为参数传递给另外一个函数。const execute = (someFunction) => someFunction()
execute(() => alert(‘Executed’))
也可以在在函数中返回一个函数:const getOne = () => () => 1
getOne()()
之所以在 getOne 后面有两个 () ,是因为第一个返回的返回值是一个函数。如下:const getOne = () => () => 1
getOne //=> () => () => 1
getOne() //=> () => 1
getOne()() //=> 1
从函数返回函数可以帮助我们追踪初始输入函数。例如,下面的函数接受一个数字作为参数,并返回一个将该参数乘以新参数的函数:
const multiply = (x) => (y) => x * y
multiply(5)(20)
这个示例跟上述 getOne 一样,在下面这个例子,让 x = 5,y = 20。const multiply = (x) => (y) => x * y
multiply //=> (x) => (y) => x * y
multiply(5) //=> (y) => 5 * y
multiply(5)(20) //=> 5 * 20
在只传入一个参数调用 multiply 函数时,即部分调用该函数。比如,multiply(5) 讲得到一个将其输入值乘以 5 的函数,multiply(7) 将得到一个将其输入值乘以 7 的函数。依此类推。通过部分调用可以创建一个预定义功能的新函数:
const multiply = (x) => (y) => x * y
const multiplyByFive = multiply(5)
const multiplyBy100 = multiply(100)multiplyByFive(20) //=> 100
multiply(5)(20) //=> 100
multiplyBy100(5) //=> 500
multiply(100)(5) //=> 500
一开始看起来似乎没什么用,但是,通过部分调用这种方式可以编写可读性更高,更易于理解的代码。举个例子,可以用一种更清晰的方式来代替 style-components 的函数插入语法。
// before
const Button = styled.buttonbackground-color: ${({ theme }) => theme.bgColor} color: ${({ theme }) => theme.textColor}
Submit
// after
const fromTheme = (prop) => ({ theme }) => theme[prop]const Button = styled.button
background-color: ${fromTheme("bgColor")} color: ${fromTheme("textColor")}
Submit
我们创建一个接受一个字符串作为参数的函数 fromTheme(“textColor”):它返回一个接受具有 theme 属性的对象的函数:({ theme }) => theme[prop],然后再通过初始传入的字符串 “textColor” 进行查找。我们可以做得更多,写类似的 backgroundColor 和 textColor 这种部分调用 fromTheme 的函数:const fromTheme = (prop) => ({ theme }) => theme[prop]
const backgroundColor = fromTheme(“bgColor”)
const textColor = fromTheme(“textColor”)const Button = styled.button
background-color: ${backgroundColor} color: ${textColor}
Submit
高阶函数
高阶函数的定义是,接受函数作为参数的函数。如果曾经使用过类似 map 这样的函数,可能已经很熟悉高阶函数。如果不熟悉 map,它是一个数组遍历的方法,接受一个函数作为参数应用到数组中的每个元素。例如,可以像这样对一个数组作平方:const square = (x) => x * x
[1, 2, 3].map(square) //=> [ 1, 4, 9 ]
可以实现一个我们自己的 map 版本来说明这个概念:const map = (fn, array) => {
const mappedArray = []for (let i = 0; i < array.length; i++) { mappedArray.push( // apply fn with the current element of the array fn(array[i]) ) } return mappedArray
}
然后再使用我们的 map 版本来对一个数组作平方:const square = (x) => x * x
console.log(map(square, [1, 2, 3, 4, 5])) //=> [ 1, 4, 9, 16, 25 ]
译者注:我们也可以将 map 方法从对象中解耦出来:const map = (fn, array) => Array.prototype.map.call(array, fn)
这样也可以像上述例子一样调用。 或者更函数式的做法,再来点柯里化:
const map = array => fn => Array.prototype.map.call(array, fn)
或者是返回一个
- 的 React 元素数组:
const HeroList = ({ heroes }) => (
- {hero}
{map((hero) => (
), heroes)}
)<HeroList heroes=[
“Wonder Woman”,
“Black Widow”,
“Spider Man”,
“Storm”,
“Deadpool”
]/>/=> (
- Wonder Woman
- Black Widow
- Spider Man
- Storm
- Deadpool
)/
高阶组件
我们知道,高阶函数是接受函数作为参数的函数。在 React 中,任何返回 JSX 的函数都被称为无状态函数组件,简称为函数组件。基本的函数组件如下所示:const Title = (props) =>
{props.children}
ReactDOM.render(
Higher-Order Components(HOCs) for React Newbies ,
document.getElementById(‘app’)
)高阶组件则是接受组件作为参数并返回组件的函数。如何使用传入组件完全取决于你,甚至可以完全忽视它:
// Technically an HOC
const ignore = (anything) => (props) =>😃
const IgnoreHeroList = ignore(‘HeroList’)
ReactDOM.render(
,
document.getElementById(‘app’)
)可以编写一个将输入转换成大写的 HOC:
const yell = (PassedComponent) =>
({ children, …props }) =>
<PassedComponent {…props}>
{children.toUpperCase()}!
const Title = (props) =>
{props.children}
const AngryTitle = yell(Title)ReactDOM.render(
Whatever,
document.getElementById(‘app’)
)你也可以返回一个有状态组件,因为 JavaScript 中的类不过是函数的语法糖。这样就可以使用到 React 生命周期的方法,比如 componentDidMount。这是 HOCs 真正有用的地方。我们现在可以做一些稍微有趣点的事,比如将 HTTP 请求的结果传递给函数组件。
const withGists = (PassedComponent) =>
class WithGists extends React.Component {
state = {
gists: []
}componentDidMount() { fetch("https://api.github.com/gists/public") .then((r) => r.json()) .then((gists) => this.setState({ gists: gists })) } render() { return ( <PassedComponent {...this.props} gists={this.state.gists} /> ) }
}
const Gists = ({ gists }) => (
{JSON.stringify(gists, null, 2)}
)const GistsList = withGists(Gists)
// => Before api request finishes:
//
//
// => After api request finishes:
// <Gists gists={[
// { /* … / },
// { / … / },
// { / … */ }
// ]} />
withGists 会传递 gist api 调用的结果,并且你可以在任何组件上使用。点击这里 可以看到一个更加完整的例子。结论:高阶组件是
react-redux 也是使用 HOC, connect 将应用 store 的值传递到“已连接” 的组件。它还会执行一些错误检查和组件生命周期优化,如果手动完成将导致编写大量重复代码。如果你发现自己在不同地方编写了大量的代码,那么也可以将代码重构成可重用的 HOC。
HOCs 非常具有表现力,可以使用它们创造很多很酷的东西。
尽可能地保持你的 HOC 简单,不要编写需要阅读长篇大论才能理解的代码。
-
redux6 - 实现 react-redux 前置技能react 高阶组件的使用
2020-06-02 09:27:39代码太多,就放codesandbox.io 了,可以看到,在组件中连接仓库和组件的一个重要方法, connect() ,该方法的返回值就是个高阶组件 什么是高阶组件 高阶组件: 同高阶函数,参数可以是组件, 或者返回一个组件, ...react-redux使用演示
代码太多,就放
codesandbox.io
了,可以看到,在组件中连接仓库和组件的一个重要方法,connect()
,该方法的返回值就是个高阶组件
什么是高阶组件
- 高阶组件: 同高阶函数,参数可以是组件, 或者返回一个组件,
- 使用场景: 一般用于公共部分的抽离,对一个组件进行包装,让它产生一些新的功能,或者返回一个新的UI组件
class App extends Component { render() { return ( <> <h1>我是被包装后的组件</h1> <span>{this.props.msg}</span> <h2 style={{ color: this.props.color }}>{this.props.info}</h2> </> ); } } function connect(WarpComponent) { return class extends Component { state = { msg: '高阶组件', info: '二柱子,萨斯给', }; componentDidMount() { this.setState({ color: '#f65', }); } render() { return ( <div> <p>hello,我是高阶组件</p> <WarpComponent {...this.state} /> </div> ); } }; } App = connect(App); ReactDOM.render(<App />, document.getElementById('root'));
再比如说,前边的redux使用时,在每个
CounA
和CoutB
组件都写了以下代码,那这个代码就可以拆出来了componentDidMount() { this.unsubscribe = store.subscribe(() => this.setState({ num: store.getState().count1.num }), ); } componentWillUnmount() { this.unsubscribe(); }
-
高阶组件相关知识点详解
2019-12-31 16:18:57高阶组件理解 本章节,我们将深入高阶组件详细了解,高阶组件相关的知识点,包括什么是高阶组件,以及如何创建高阶组件,高阶组件实现的几种方式,常用的使用场景等等; ...高阶组件知识点理解
本章节,我们将深入高阶组件详细了解,高阶组件相关的知识点,包括什么是高阶组件,以及如何创建高阶组件,高阶组件实现的几种方式,常用的使用场景等等;首先我们需要来了解下,和高阶组件非常类似的一个概念,
高阶函数
:如果一个函数操作其他函数,将其他函数作为参数或返回值,将其称为高阶函数。-
关于高阶组件的概念:
高阶组件
(high-order component)类似于高阶函数,接收 React 组件作为输入,输出一个新的 React 组件。高阶组件让代码更具有复用性、逻辑性与抽象特征。可以对render
方法作劫持,也可以控制props
与state
。 -
实现高阶组件的方法有如下
2
种:- 属性代理(
props proxy
):属性组件通过被包裹的React
组件来操作props
。 - 反向代理(
inheritance inversion
):高阶组件继承于被包裹的React
组件。
- 属性代理(
第一种方法:属性代理
属性代理是比较常见的一种高阶组件的实现方法。如下:
const MyContainer = (WrappedComponent) => { return class extends Component { render() { return ( <WrappedComponent {...props} /> ) } } } export default MyContainer;
在
render
方法中返回传入WrappedComponent
的React
组件。这样就可以通过高阶组件来传递props
,这种方法即为属性代理。当然,原始组件想要具备高阶组件对它的修饰,有下面两种方式:
第1种方式
export default MyContainer; class MyComponent extends Component { } export default MyContainer(MyComponent);
第2种方式
使用
ES7
中的decorator
的属性,我们可以通过decorator
来转换,以此简化高阶组件的调用。@MyContainer class MyComponent extends Component { } export default MyComponent;
控制
props
我们可以读取、增加、编辑或是移除从
WrappedComponent
传进来的props
,但需要小心删除与编辑重要的props
。应该尽量对高阶组件的props
作新的命名以防止混淆。const MyContainer = (WrappedComponent) => { return class extends Component { render() { const newProps = { text: newText }; return ( <WrappedComponent {...props} {...newProps} /> ) } } } export default MyContainer;
从上面这个案例看来,当调用这个
MyContainer
高阶组件时,就可以使用text
这个新的props
了。通过
refs
使用引用在高阶组件中,可以接受
refs
使用WrappedComponent
的引用。const MyContainer = (WrappedComponent) => { return class extends Component { ref = (view) => { view.mentod(); } render() { const props = Object.assign({}, this.props, { ref: this.ref }); return ( <WrappedComponent {...props} /> ) } } } export default MyContainer;
抽象
state
可以通过
WrappedComponent
提供的props
和回调函数抽象state
。将原组件抽象为展示型组件,分离内部状态 。const MyContainer = (WrappedComponent) => { return class extends Component { constructor(props); super(props); this.state = { name: '' }; } onNameChange(text) { this.setState({ name: text }); } render() { const newProps = { name = { value: this.state.name, onChangeText: { this.onNameChange } } } return ( <WrappedComponent {...this.props} {...newProps} /> ); } } export default MyContainer;
使用情况如下:
@MyContainer class MyComponent extends Component { render() { return ( <TextInput {...this.props.name} /> ); } }
使用其他元素包裹
WrappedComponent
export default LoginPleaseMixin; const MyContainer = (WrappedComponent) => { return class exrends PureComponent { render() { return ( <View> <WrappedComponent /> </View> ); } } } export default MyContainer;
第二种方法:反向继承
反向继承是另一种构建高阶组件的方法。
const MyContainer = (WrappedComponent) => { return class extends WrappedComponent { render() { return super.render(); } } } export default MyContainer;
高阶组件返回的组件继承于
WrappedComponent
。因为被动地继承了WrappedComponent
,所有的调用都会反向。
通过继承WrappedComponent
来实现,方法可以通过super
来顺序调用。
在反向继承方法中,高阶组件可以使用WrappedComponent
引用,这意味着它可以使用WrappedComponent
的state
、props
、生命周期和render
方法,但他不能保证完整的子组件树被解析。渲染劫持
概念:渲染劫持指的就是高阶组件可以控制
WrappedComponent
的渲染过程,并渲染各种各样的结果。我们可以在这个过程中在任何React
元素输出的结果中读取、增加、修改、删除 props,或读取或修改 React 元素树、或条件显示元素树,又或是用样式控制包裹元素树。
反向继承不能保证完整的子组件树被解析,这意味着将限制渲染劫持功能。但是如果元素树包裹了函数类型的 React 组件,就不能操作组件的子组件。- 条件渲染:
const MyContainer = (WrappedComponent) => { return class extends WrappedComponent { render() { if (this.props.loggIn) { return super.render(); } else { return null; } } } } export default MyContainer;
- 对
render
输出结果进行修改:
//... const MyContainer = (WrappedComponent) => { return class extends WrappedComponent { render() { const elementsTree = super.render(); let newProps = {}; if (elementsTree && elementsTree.type === 'input') { newProps = {value: 'may the force be with you'}; } const props = Object.assign({}, elementsTree.props, newProps); const newElementsTree = React.cloneElement(elementsTree, props, elementsTree.props.children); return newElementsTree; } } } export default MyContainer;
在这里,我们可以做各种各样的事,甚至可以反转元素树,或是改变元素树中的
props
。控制
state
高阶组件可以读取、修改或删除 WrappedComponent 实例中的 state,如果需要的话,也可以增加 state。但是这样做,可能让 WrappedComponent 组件内部状态变得一团糟。大部分的高阶组件都应该限制读取或增加 state,尤其是后者,可以通过重新命名 state,以防止混淆。
const MyContainer = (WrappedComponent) => { return class extends WrappedComponent { render() { return ( <View> <Text> {JSON.stringify(this.props)} </Text> <Text> {JSON.stringify(this.state)} </Text> {super.render()} </View> ); } } } export default MyContainer;
组件命名
当包裹一个高阶组件时,我们失去了原始的
WrappedComponent
的displayName
,而组件名字是方便我们开发与调试的重要属性。HOC.displayName = `HOC{${getDisplayName(WrappedComponent)}}`; class HOC extends ... { static displayName = `{Hoc(${getDisplayName(WrappedComponent)})}` function getDisplayName(WrappedComponent) { return WrappedComponent.displayName || WrappedComponent.name || 'Component'; } }
组件参数
调用高阶组件时需要传入一些参数,可以用简单方式实现。
function HOCFactoryFactory(...params) { return function HOCFactory(WrappedComponent) { return class HOC extends Component { render() { return ( <WrappedComponent {...this.props} /> ); } } } }
使用如下:
HOCFactoryFactory(params)(WrappedComponent) // or @HOCFactoryFactory(params) class WrappedComponent extends Component { //... }
-
-
装饰器+HOC(高阶组件)简单使用
2020-04-24 09:51:21装饰器+HOC(高阶组件)简单使用 这里不会过多的详细介绍HOC和装饰器的概念,而是简单叙述实际开发场景中是一个demo来作为使用参考。 高阶组件 简单来说,高阶组件是一个函数,能够接受一个组件并返回一个新的组件。 ... -
React 高阶组件
2018-03-11 07:27:19高阶组件的作用主要是用来加强组件,通过把基础组件拆分成很小的粒度,通过高阶组件进行增强并返回,以此提高复用性。 比如需要开发一个消息框,一开始只需要一个模态框能够显示消息就可以。后来需要多增加『确定』... -
浅谈React高阶组件
2020-12-12 00:17:31但经过了种种衡量,最后选择使用了高阶组件的做法。 那什么是高级组件?首先你得先了解请求ES6中的class只是语法糖,本质还是原型继承。能够更好的进行说明,我们将不会修改组件的代码。而是通过提供一些能够包裹... -
React高阶组件HOC
2021-02-15 15:14:55文章目录react-native高阶组件HOC一、定义 ...反向继承)四、基类还是高阶组件的选择五、HOC示例5.1、react-navigation中的使用5.2、react官网示例六、使用HOC需要注意什么6.1、尽量不要随意修改下级组件需要的props6.2 -
react高阶组件
2018-04-09 06:48:09高阶组件不是组件,而是一个普通的函数,传入一个组件,返回一个...1.高阶组件的实现 import React,{Component} from 'react'; import ReactDOM from 'react-dom'; import UserName from './UserName'; import Mobil... -
React高阶组件
2018-03-27 20:00:08前段时间在工作中写Hybrid页面时遇到了这样的一个场景,公司需要一系列的活动组件,在每个...但经过了种种衡量,最后选择使用了高阶组件的做法。 1、Mixins的缺点 React官方已不推荐使用Mixins的技术来实现代码的... -
React高阶组件实例应用
2020-07-12 11:32:391.为何使用高阶组件 实现逻辑复用,例如:用户对页面按钮操作的权限控制。 2.什么是高阶组件 React官网:具体而言,高阶组件是参数为组件,返回值为新组件的函数。 3.应用场景 鉴权判断 举个栗子: 下面代码是三块... -
React 高阶组件 HOC
2019-01-24 16:10:31基本概念 在javascript中,高阶函数是...高阶组件本质上也是一个函数。 形式: const EnhancedComponent = heigherComponent(WrappedComponent) 使用场景 1. 操作props,添加,删除,修改 在被包装组件接受props前... -
深入react 高阶组件
2018-06-11 15:16:18高阶组件:返回值是一个函数的那么一个函数 基本算是个类工厂方法 W (WrappedComponent) 是被包裹的 React.Component;而函数返回的 E (Enhanced Component) 则是新得到的 HOC,也是个 React.Component使用场景:... -
react 给一个引用的组件添加新属性_高阶组件在React中的应用
2021-02-04 00:44:53高阶组件的定义接受React组件作为输入,输出一个新的React组件。概念源自于高阶函数,将函数作为参数,或者输出一个函数,如map,reduce,sort。 用haskell的函数签名来表示: hocFactory:: W: React.component =>... -
React组件重构之嵌套+继承及高阶组件详解
2020-12-10 05:40:03但是后来又用高阶组件重新写了一遍,发现更好一点。 在这里记录下这两种方式以便之后参考和演进。 本次重构的场景 因为场景涉及到具体的业务,所以我现在将它简化为一个简单的场景。 现在有两个黑色箱子,箱子上... -
组件加name属性_高阶组件
2021-01-12 00:49:50首次使用场景项目初期只有一个添加商品模块,因业务迭代...高阶组件。公共逻辑抽离方案,公共逻辑中包含了state、props、以及setState,如果提取公共逻辑代码,势必重新处理相关状态,对原有模块破坏性大。公共容器组... -
render注册一个链接组件_学习笔记-高阶组件
2020-12-03 05:43:11高阶组件首次使用场景项目初期只有一个添加商品模块,因业务迭代,从多图商品中分离出视频商品,当前存在的问题:版本迭代势必势必同时修改两个模块;大量逻辑,方法重复。方案筛选鉴于以上问题,寻找的解决方案有:... -
react进阶之高阶组件
2021-01-02 06:55:07高阶组件的定义我都是用箭头函数去写的,如有不适请参照<a href="http://es6.ruanyifeng.com/#docs/function#%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0">arrow function</a></p> 装饰器模式 高阶组件可以看做是... -
「react进阶」一文吃透React高阶组件(HOC)
2021-03-20 15:05:15React高阶组件(HOC),对于很多react开发者来说并不陌生,它是灵活使用react组件的一种技巧,高阶组件本身不是组件,它是一个参数为组件,返回值也是一个组件的函数。高阶作用用于强化组件,复用逻辑,提升渲染性能等... -
react中高阶函数的使用
2020-12-12 10:24:31高阶组件使应用场景 目的: 把常用的逻辑独出来进行多次复用 业务场景: 在一个多页H5中,部分页面有查看权限,比如新闻列表,详情,不需要进行任何操作就可以看。但是比如活动抽奖页,如果想参加就需要验证手机号... -
React手稿之高阶组件
2018-11-15 14:55:36Higher-Order Components HOC 不是React的标准API。 HOC 是一个函数。 HOC 返回一个Component。 示例: const EnhancedComponent = higherOrderComponent...使用场景 代码复用 类似React 0.15版本之... -
antd表单性能改进实践 debounce 高阶组件
2019-03-24 16:47:23摘要 随着es2015、babel等技术在前端迅速...随着使用场景的变化,又有许多性能问题暴露出来。因此继续研究antd的性能问题,寻找最终解决方案。 antd简介 antd是由阿里旗下的 蚂蚁金服体验技术部 开发的一套UI设计语... -
由重构react组件引发的函数式编程的思考
2017-07-28 04:00:19对于高阶组件的使用场景如果有相关经验的或者有不同的见解的希望能够在我的博客下面留言 最近在重构react组件时,学习了一些高阶组件的编写思路,其实是由高阶函数沿伸而来。一般情况我们编写一个react组件大致样子...