一、高阶函数
概念:高阶函数是一个函数,它接收函数作为参数或将函数作为输出返回
- 举个栗子:
- 接收函数作为参数 ```javascript function a(x) { x(); } function b() { alert(‘hello’); }
a(b);
- 将函数作为输出返回
```javascript
function a() {
function b() {
alert('hello');
}
return b;
}
a()();
- 以上函数a就是一个高阶函数, 用法非常简单, 那么实际开发中又有哪些是高阶函数呢?
- Array 的 map 、reduce 、filter 等方法
- Object 的 keys 、values 等方法
- Array 的 map 、reduce 、filter 等方法
二、高阶组件
概念:**高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件**
- 举个栗子: ```javascript import React from ‘react’; import logo from ‘./logo.svg’; import ‘./App.css’;
class MyComponent extends React.Component{ render(){ return (
Hello React
) } } function HocComponent(WrappedComponent){ return class extends React.Component{ render(){ returnconst NewComponent = HocComponent(MyComponent)
function App() {
return (
export default App;
Tip:HocComponent函数就是一个高阶组件。
<a name="wOL05"></a>
### 2-1 高阶组件的实现方式-->属性代理
属性代理的作用:
- 更改prop<br />
- 通过refs获取组件实例<br />
- 抽象state<br />
- 把WrappedComponent与其他elements包装在一起
<a name="FTHLb"></a>
#### 2-1-1 属性代理-更改props
在高阶组件中添加新的 props,可以在 WrappedComponent 中通过 this.props.name访问到。
```javascript
import React from 'react';
import logo from './logo.svg';
import './App.css';
class MyComponent extends React.Component{
render(){
return (<p>Hello React {this.props.name}</p>)
}
}
function HocComponent(WrappedComponent){
return class extends React.Component{
render(){
return <WrappedComponent {...this.props}/>
}
}
}
const NewComponent = HocComponent(MyComponent)
function App() {
return (
<NewComponent name="zhangsan"></NewComponent>
);
}
export default App;
2-1-2 属性代理-通过refs获取组件实例
可以通过引用(ref)访问到 this (WrappedComponent 的实例),但为了得到引用,WrappedComponent 还需要一个初始渲染,意味着你需要在 HOC 的 render 方法中返回 WrappedComponent 元素,让 React 开始它的一致化处理,你就可以得到 WrappedComponent 的实例的引用。
import React from 'react';
import logo from './logo.svg';
import './App.css';
class MyComponent extends React.Component {
say(){
console.log("say say say .....")
}
render() {
return (<p>Hello React {this.props.name}</p>)
}
}
function HocComponent(WrappedComponent) {
return class extends React.Component {
//此处的instance会拿到被包装的组件实例,然后访问被包装的组件对象的属性和方法
proc(instance) {
instance.say();
console.log(instance.props.name)
}
render() {
return <WrappedComponent {...this.props} ref={this.proc} />
}
}
}
const NewComponent = HocComponent(MyComponent)
function App() {
return (
<NewComponent name="zhangsan"></NewComponent>
);
}
export default App;
2-1-3 属性代理-抽取state
import React from 'react';
import logo from './logo.svg';
import './App.css';
class MyInput extends React.Component {
constructor(props){
super(props);
this.state = {
value:""
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event){
this.setState({
value:event.target.value
})
}
render() {
return (<input value={this.state.value} onChange={this.handleChange}></input>)
}
}
class MyTextArea extends React.Component {
constructor(props){
super(props);
this.state = {
value:""
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event){
this.setState({
value:event.target.value
})
}
render() {
return (<textarea value={this.state.value} onChange={this.handleChange}></textarea>)
}
}
function HocComponent(WrappedComponent) {
return class extends React.Component {
render() {
return <WrappedComponent/>
}
}
}
const NewInput = HocComponent(MyInput)
const NewTextArea = HocComponent(MyTextArea)
function App() {
return (
<div>
<NewInput></NewInput>
<NewTextArea></NewTextArea>
</div>
);
}
export default App;
//这边代码存在的问题:MyInput和MyTextArea组件都有自己的state和change方法,代码重用性太大
import React from 'react';
import logo from './logo.svg';
import './App.css';
class MyInput extends React.Component {
render() {
return (<input value={this.props.value} onChange={this.props.onChange}></input>)
}
}
class MyTextArea extends React.Component {
render() {
return (<textarea value={this.props.value} onChange={this.props.onChange}></textarea>)
}
}
function HocComponent(WrappedComponent) {
return class extends React.Component {
//将所有被包含组件的state和change都抽取到高阶组件中
constructor(props) {
super(props);
this.state = {
value: ""
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event) {
this.setState({
value: event.target.value
})
}
render() {
const newProps = {
value: this.state.value,
onChange: this.handleChange
}
return (
//向被包含组件传递属性
<WrappedComponent {...this.props} {...newProps} />
)
}
}
}
const NewInput = HocComponent(MyInput)
const NewTextArea = HocComponent(MyTextArea)
function App() {
return (
<div>
<NewInput></NewInput>
<NewTextArea></NewTextArea>
</div>
);
}
export default App;
2-1-4 属性代理-用其他元素包装组件
为了封装样式、布局或别的目的,可以用其它组件和元素包裹 WrappedComponent。基本方法是使用父组件实现,但通过 HOC 可以得到更多灵活性。
import React from 'react';
import logo from './logo.svg';
import './App.css';
class MyComponent extends React.Component {
render() {
return (<p>被包裹组件</p>)
}
}
function HocComponent(WrappedComponent) {
return class extends React.Component {
render() {
return (
<div style={{color:"red"}}>
<WrappedComponent {...this.props} />
</div>
)
}
}
}
const NewComponent = HocComponent(MyComponent)
function App() {
return (
<div>
<NewComponent></NewComponent>
</div>
);
}
export default App;
2-2 高阶组件的实现方式-反向继承
反向继承的作用:
- 渲染劫持
- 操作state
返回的 HOC 类(Enhancer)继承了 WrappedComponent。之所以被称为 Inheritance Inversion 是因为 WrappedComponent 被 Enhancer 继承了,而不是 WrappedComponent 继承了 Enhancer。在这种方式中,它们的关系看上去被反转(inverse)了。function iiHOC(WrappedComponent) {
return class Enhancer extends WrappedComponent {
render() {
return super.render()
}
}
}
2-2-1 反向继承-渲染劫持
之所以被称为渲染劫持是因为 HOC 控制着 WrappedComponent 的渲染输出,可以用它做各种各样的事。通过渲染劫持可以:
在由 render输出的任何 React 元素中读取、添加、编辑、删除 props
读取和修改由 render 输出的 React 元素树
有条件地渲染元素树
把样式包裹进元素树(就像在 Props Proxy 中的那样)
import React from 'react';
import logo from './logo.svg';
import './App.css';
class MyComponent extends React.Component {
render() {
return (<p name="pp">被包裹组件</p>)
}
}
function iiHOC(WrappedComponent) {
return class Enhancer extends WrappedComponent {
render() {
const elementsTree = super.render();
//打印父组件的属性值
console.log(elementsTree.props)
//添加新的 属性返回
let newProps = {style:{color:'red'}};
const props = Object.assign({},elementsTree.props,newProps);
const newElement = React.cloneElement(elementsTree, props, elementsTree.props.children)
return newElement;
}
}
}
const NewComponent = iiHOC(MyComponent)
function App() {
return (
<div>
<NewComponent></NewComponent>
</div>
);
}
export default App;
2-2-2 反向继承-修改state
HOC 可以读取、编辑和删除 WrappedComponent 实例的 state,如果需要,也可以给它添加更多的 state。但是这会搞乱 WrappedComponent 的 state,可能会导致破坏某些东西,通常不建议使用高阶组件修改添加state。
通过访问 WrappedComponent 的 props 和 state 来做调试。
这里 HOC 用其他元素包裹着 WrappedComponent,还输出了 WrappedComponent 实例的 props 和 state。
export function IIHOCDEBUGGER(WrappedComponent) {
return class II extends WrappedComponent {
render() {
return (
<div>
<h2>HOC Debugger Component</h2>
<p>Props</p> <pre>{JSON.stringify(this.props, null, 2)}</pre>
<p>State</p><pre>{JSON.stringify(this.state, null, 2)}</pre>
{super.render()}
</div>
)
}
}
}