该函数接收三个零件并且重回一个新组件,该函数接收贰个组件并且重回一个新组件

1.在React中higher-order component
(HOC)是一种重用组件逻辑的尖端才干。HOC不是React API中的一片段。HOC是三个函数,该函数接收三个零件并且重回七个新组件。在React中,组件是代码复用的着力单位。

1.在React中higher-order component
(HOC)是一种重用组件逻辑的尖端能力。HOC不是React
API中的一局地。HOC是一个函数,该函数接收三个零件并且重临一个新组件。在React中,组件是代码复用的为主单位。

2.为了解说HOCs,举上边多少个例证

2.为了疏解HOCs,举上面多个例证

 

CommentList组件会渲染出一个comments列表,列表中的数据出自于外界。

CommentList组件会渲染出一个comments列表,列表中的数据来自于外部。

class CommentList extends React.Component {
   constructor() {
     super();
     this.handleChange = this.handleChange.bind(this);
     this.state = {
       // "DataSource" is some global data source
       comments: DataSource.getComments()
     };
   }

   componentDidMount() {
     // Subscribe to changes
     DataSource.addChangeListener(this.handleChange);
   }

   componentWillUnmount() {
     // Clean up listener
     DataSource.removeChangeListener(this.handleChange);
   }

   handleChange() {
     // Update component state whenever the data source changes
     this.setState({
       comments: DataSource.getComments()
     });
   }

   render() {
     return (
       <div>
         {this.state.comments.map((comment) => (
           <Comment comment={comment} key={comment.id} />
         ))}
       </div>
     );
   }
 }
class CommentList extends React.Component {

  constructor() {

   super();

   this.handleChange = this.handleChange.bind(this);

   this.state = {

    // "DataSource" is some global data source

    comments: DataSource.getComments()

   };

  }



  componentDidMount() {

   // Subscribe to changes

   DataSource.addChangeListener(this.handleChange);

  }



  componentWillUnmount() {

   // Clean up listener

   DataSource.removeChangeListener(this.handleChange);

  }



  handleChange() {

   // Update component state whenever the data source changes

   this.setState({

    comments: DataSource.getComments()

   });

  }



  render() {

   return (

    <div>

     {this.state.comments.map((comment) => (

      <Comment comment={comment} key={comment.id} />

     ))}

    </div>

   );

  }

 } 

 接下来是BlogPost组件,这么些组件用于呈现一篇博客新闻

 接下来是BlogPost组件,这么些组件用于显示一篇博客音信

class BlogPost extends React.Component {
   constructor(props) {
     super(props);
     this.handleChange = this.handleChange.bind(this);
     this.state = {
       blogPost: DataSource.getBlogPost(props.id)
     };
   }

   componentDidMount() {
     DataSource.addChangeListener(this.handleChange);
   }

   componentWillUnmount() {
     DataSource.removeChangeListener(this.handleChange);
   }

   handleChange() {
     this.setState({
       blogPost: DataSource.getBlogPost(this.props.id)
     });
   }

   render() {
     return <TextBlock text={this.state.blogPost} />;
   }
 }
class BlogPost extends React.Component {

  constructor(props) {

   super(props);

   this.handleChange = this.handleChange.bind(this);

   this.state = {

    blogPost: DataSource.getBlogPost(props.id)

   };

  }



  componentDidMount() {

   DataSource.addChangeListener(this.handleChange);

  }



  componentWillUnmount() {

   DataSource.removeChangeListener(this.handleChange);

  }



  handleChange() {

   this.setState({

    blogPost: DataSource.getBlogPost(this.props.id)

   });

  }



  render() {

   return <TextBlock text={this.state.blogPost} />;

  }

 } 

 这多个零部件是分歧等的,它们调用了DataSource的比不上如式,并且它们的出口也不均等,然则它们中的超过十分之五落到实处是一律的:

那四个零件是不等同的,它们调用了DataSource的不等方法,并且它们的出口也不相同等,但是它们中的超越四分之二贯彻是一模二样的:

1.装载成功后,给DataSource增添了三个change listener
2.当数据源发生变化后,在监听器内部调用setState
3.卸载之后,移除change
listener

1.装载完了后,给DataSource增多了八个change listener
2.当数据源发生变化后,在监听器内部调用setState
3.卸载之后,移除change listener

能够想像在巨型应用中,一样情势的访问DataSource和调用setState会贰遍又一次的产生。大家盼望抽象那些进程,从而让大家只在贰个位置定义这么些逻辑,然后
在四个零部件中国共产党享。

能够想象在巨型应用中,一样格局的访问DataSource和调用setState会贰遍又三次的发出。大家意在抽象这个进度,从而让大家只在二个地点定义那么些逻辑,然后在多个零部件中国共产党享。

接下去大家写三个创制组件的函数,这一个函数接受五个参数,个中一个参数是组件,另几个参数是函数。上面调用withSubscription函数

接下去大家写一个开立组件的函数,那个函数接受五个参数,在那之中二个参数是组件,另二个参数是函数。下边调用withSubscription函数

 

const CommentListWithSubscription = withSubscription(

 CommentList,

 (DataSource) => DataSource.getComments()

);



const BlogPostWithSubscription = withSubscription(

 BlogPost,

 (DataSource, props) => DataSource.getBlogPost(props.id)

); 
const CommentListWithSubscription = withSubscription(
  CommentList,
  (DataSource) => DataSource.getComments()
);

const BlogPostWithSubscription = withSubscription(
  BlogPost,
  (DataSource, props) => DataSource.getBlogPost(props.id)
);

调用withSubscription传的第2个参数是wrapped
组件,第一个参数是贰个函数,该函数用于检索数据。

 

当CommentListWithSubscription和BlogPostWithSubscription被渲染,CommentList和BlogPost会接受贰个称为data的prop,data中保存了近期从DataSource中追寻出的多少。withSubscription代码如下:

 调用withSubscription传的第叁个参数是wrapped
组件,第2个参数是三个函数,该函数用于检索数据。
当CommentListWithSubscription和BlogPostWithSubscription被渲染,CommentList和BlogPost会接受贰个称得上data的prop,data中保留了现阶段
从DataSource中搜索出的数额。withSubscription代码如下:

// This function takes a component...

function withSubscription(WrappedComponent, selectData) {

 // ...and returns another component...

 return class extends React.Component {

  constructor(props) {

   super(props);

   this.handleChange = this.handleChange.bind(this);

   this.state = {

    data: selectData(DataSource, props)

   };

  }



  componentDidMount() {

   // ... that takes care of the subscription...

   DataSource.addChangeListener(this.handleChange);

  }



  componentWillUnmount() {

   DataSource.removeChangeListener(this.handleChange);

  }



  handleChange() {

   this.setState({

    data: selectData(DataSource, this.props)

   });

  }



  render() {

   // ... and renders the wrapped component with the fresh data!

   // Notice that we pass through any additional props

   return <WrappedComponent data={this.state.data} {...this.props} />;

  }

 };

} 

 

 HOC并不曾改造输入的组件,也从未利用持续去重用它的表现。HOC只是四个函数。wrapped
组件接受了容器的所以props,同期还接受了二个新的prop(data),data用于渲染wrapped
组件的输出。HOC不关怀数据怎么使用也不关心数据为啥选取,wrapped组件不爱抚数据是何方获得。

// This function takes a component...
function withSubscription(WrappedComponent, selectData) {
  // ...and returns another component...
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.handleChange = this.handleChange.bind(this);
      this.state = {
        data: selectData(DataSource, props)
      };
    }

    componentDidMount() {
      // ... that takes care of the subscription...
      DataSource.addChangeListener(this.handleChange);
    }

    componentWillUnmount() {
      DataSource.removeChangeListener(this.handleChange);
    }

    handleChange() {
      this.setState({
        data: selectData(DataSource, this.props)
      });
    }

    render() {
      // ... and renders the wrapped component with the fresh data!
      // Notice that we pass through any additional props
      return <WrappedComponent data={this.state.data} {...this.props} />;
    }
  };
}

因为withSubscription只是八个例行的函数,你能增加肆意个数的参数。举例,你能让data
prop的名字是可布署的,从而进一步将HOC与wrapped组件隔开分离。

 

依然收受一个布局shouldComponentUpdate,大概配备数据源的参数

 HOC并从未改造输入的机件,也未曾使用持续去重用它的作为。HOC只是贰个函数。wrapped 组件接受了容器的所以props,同期还接受了贰个新的prop(data),data
用于渲染wrapped 组件的输出。HOC不关心数据怎么利用也不关心数据为何使用,wrapped组件不爱抚数据是何方获得。
因为withSubscription只是贰个正规的函数,你能增添大陆个数的参数。比方,你能让data
prop的名字是可安插的,从而进一步将HOC与wrapped组件隔绝。
照旧接受三个布局shouldComponentUpdate,也许配备数据源的参数

行使高阶组件时有个别须要小心的地点。

使用高阶组件时有个别需求留神的地点。

1.毫无改造原始组件,那点很要紧

1.永不改换原始组件,那点很关键

有如下例子:

有如下例子:

function logProps(InputComponent) {

 InputComponent.prototype.componentWillReceiveProps = function(nextProps) {

  console.log('Current props: ', this.props);

  console.log('Next props: ', nextProps);

 };

 // The fact that we're returning the original input is a hint that it has

 // been mutated.

 return InputComponent;

}



// EnhancedComponent will log whenever props are received

const EnhancedComponent = logProps(InputComponent); 
function logProps(InputComponent) {
  InputComponent.prototype.componentWillReceiveProps = function(nextProps) {
    console.log('Current props: ', this.props);
    console.log('Next props: ', nextProps);
  };
  // The fact that we're returning the original input is a hint that it has
  // been mutated.
  return InputComponent;
}

// EnhancedComponent will log whenever props are received
const EnhancedComponent = logProps(InputComponent);

这里存在一些难题,1.输入的组件不可能与增加的零部件单独重用。2.只要给EnhancedComponent应用其余的HOC,也会变动componentWillReceiveProps。

 这里存在一些问题,1.输入的零件不可能与抓实的零件单独重用。2.一旦给EnhancedComponent应用其余的HOC,也会转移componentWillReceiveProps。
其一HOC对函数类型的组件不适用,因为函数类型组件未有生命周期函数
HOC应该运用合成代替修改——通过将输入的零部件封装到容器组件中。

以此HOC对函数类型的零部件不适用,因为函数类型组件未有生命周期函数HOC应该使用合成代替修改——通过将输入的零件封装到容器组件中。

 

function logProps(WrappedComponent) {

 return class extends React.Component {

  componentWillReceiveProps(nextProps) {

   console.log('Current props: ', this.props);

   console.log('Next props: ', nextProps);

  }

  render() {

   // Wraps the input component in a container, without mutating it. Good!

   return <WrappedComponent {...this.props} />;

  }

 }

} 
function logProps(WrappedComponent) {
  return class extends React.Component {
    componentWillReceiveProps(nextProps) {
      console.log('Current props: ', this.props);
      console.log('Next props: ', nextProps);
    }
    render() {
      // Wraps the input component in a container, without mutating it. Good!
      return <WrappedComponent {...this.props} />;
    }
  }
}

其一新的logProps与旧的logProps有雷同的成效,同有的时候候新的logProps制止了暧昧的争论。对class类型的零部件和函数类型额组件同样适用。

 

2.永不在render方法中动用HOCs

 这几个新的logProps与旧的logProps有一样的成效,同一时候新的logProps幸免了隐衷的龃龉。对class类型的零部件和函数类型额组件一样适用。

React的diff算法使用组件的身价去决定是应该更新已存在的子树依旧拆除旧的子树并装载一个新的,如若从render方法中回到的机件与事先渲染的零件恒等(===),那么React会通过diff算法更新在此以前渲染的组件,借使不对等,在此之前渲染的子树会完全卸载。 

2.并非在render方法中利用HOCs

render() {

 // A new version of EnhancedComponent is created on every render

 // EnhancedComponent1 !== EnhancedComponent2

 const EnhancedComponent = enhance(MyComponent);

 // That causes the entire subtree to unmount/remount each time!

 return <EnhancedComponent />;

} 

React的diff算法使用组件的地方去决定是相应更新已存在的子树依然拆除旧的子树并装载叁个新的,假使从render方法中回到的机件与事先渲染的机件恒等(===),
那正是说React会通过diff算法更新此前渲染的机件,假使不对等,在此之前渲染的子树会完全卸载。

 在组件定义的表面使用HOCs,以至于结果组件只被创制叁遍。在少数气象下,你需求动态的采取HOCs,你该在生命周期函数恐怕构造函数中做那件事

 

3.静态方法必须手动复制

render() {
  // A new version of EnhancedComponent is created on every render
  // EnhancedComponent1 !== EnhancedComponent2
  const EnhancedComponent = enhance(MyComponent);
  // That causes the entire subtree to unmount/remount each time!
  return <EnhancedComponent />;
}

一对时候在React组件上定义静态方法是极度有效的。当您给有些组件应用HOCs,即便原始组件被包裹在容器组件里,但是回到的新组件不会有其余原始组件的静态方法。

 

// Define a static method

WrappedComponent.staticMethod = function() {/*...*/}

// Now apply an HOC

const EnhancedComponent = enhance(WrappedComponent);



// The enhanced component has no static method

typeof EnhancedComponent.staticMethod === 'undefined' // true 

 在组件定义的外界使用HOCs,以至于结果组件只被创立一次。在个别动静下,你供给动态的施用HOCs,你该在生命周期函数或然构造函数中做那件事

 为了让再次来到的机件有原始组件的静态方法,就要在函数内部将原有组件的静态方法复制给新的组件。

3.静态方法必须手动复制

function enhance(WrappedComponent) {

 class Enhance extends React.Component {/*...*/}

 // Must know exactly which method(s) to copy :(

  // 你也能够借助第三方工具

 Enhance.staticMethod = WrappedComponent.staticMethod;

 return Enhance;

} 

一些时候在React组件上定义静态方法是十一分管用的。当您给某些组件应用HOCs,固然原始组件被卷入在容器组件里,可是回去的新组件不会有任何原始组件的静态
方法。

 4.容器组件上的ref不会传递给wrapped component

 

就算容器组件上的props能够很简单的传递给wrapped
component,可是容器组件上的ref不会传递到wrapped
component。若是您给通过HOCs再次回到的零件设置了ref,这些ref援用的是最外层容器组件,而非wrapped
组件

// Define a static method
WrappedComponent.staticMethod = function() {/*...*/}
// Now apply an HOC
const EnhancedComponent = enhance(WrappedComponent);

// The enhanced component has no static method
typeof EnhancedComponent.staticMethod === 'undefined' // true

如上正是本文的全体内容,希望对我们的就学抱有帮衬,也期望大家多多帮忙脚本之家。

 

你也许感兴趣的小说:

 为了让重临的机件有原来组件的静态方法,就要在函数内部将原来组件的静态方法复制给新的零件。

function enhance(WrappedComponent) {
  class Enhance extends React.Component {/*...*/}
  // Must know exactly which method(s) to copy :(
    //  你也能够借助第三方工具
  Enhance.staticMethod = WrappedComponent.staticMethod;
  return Enhance;
}

 4.容器组件上的ref不会传递给wrapped
component

即使容器组件上的props能够很轻巧的传递给wrapped
component,不过容器组件上的ref不会传递到wrapped
component。要是你给通过HOCs重返的零部件设置了ref,这一个ref引用的是最外层容器组件,而非wrapped
组件

 

相关文章