列表中的数据出自于表面,(HOC)是一种重用组件逻辑的尖端技术

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传的首先个参数是wrapped
组件,第一个参数是一个函数,该函数用于检索数据。

 

当CommentListWithSubscription和BlogPostWithSubscription被渲染,CommentList和BlogPost会接受一个称为data的prop,data中保存了最近从DataSource中寻觅出的数目。withSubscription代码如下:

 调用withSubscription传的率先个参数是wrapped
组件,第三个参数是一个函数,该函数用于检索数据。
当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,也会变动component威·尔(W·ill)ReceiveProps。

 那里存在有的题目,1.输入的零部件不可以与增加的零部件单独重用。2.如果给EnhancedComponent应用其余的HOC,也会改变component威·尔(W·ill)ReceiveProps。
本条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
组件

 

相关文章