一、高阶函数
概念:高阶函数是一个函数,它接收函数作为参数或将函数作为输出返回
- 举个栗子:
- 接收函数作为参数 ```javascript function a(x) { x(); } function b() { alert(‘hello’); }
a(b);
- 将函数作为输出返回```javascriptfunction 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访问到。```javascriptimport 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>)}}}
