HOC不是React www.888000ff.comAPI中的一部分,该函数接收一个零件并且重临一个新组件

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威尔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 />;

} 

www.888000ff.com,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
组件

 

相关文章