您现在的位置是:网站首页> 内容页

React HOC

  • 亚米娱乐网页版
  • 2019-10-20
  • 194人已阅读
简介在React官网文档学习ReactHOC,整个看了一遍还是云里雾里的,于是按照官网文档,自己动手实践一下。官网地址:React高阶组件定义:高阶组件就是一个函数,且该函数接受一个组

在React官网文档学习React HOC,整个看了一遍还是云里雾里的,于是按照官网文档,自己动手实践一下。官网地址:React 高阶组件

定义:高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件

使用高阶组件(HOC)解决交叉问题

假设有两个组件,CommentList组件从外部数据源订阅数据并渲染评论列表,BlogPost组件是一个订阅单个博客文章的组件,该组件遵循类似的模式,即在componentDidMount中添加事件处理函数订阅数据,在componentWillUnmount中清除事件处理函数,两个组件的事件处理函数内容相同。两个组件的区别在于:从数据源订阅的数据不同,并且渲染格式不同。(代码见React官网)由此,可以将两个组件中相同的逻辑部分提取到一个高阶组件,该高阶组件能够创建类似 CommonList 和 BlogPost 从数据源订阅数据的组件 。该组件接受一个子组件作为其中的一个参数,并从数据源订阅数据作为props属性传入子组件。该高阶组件命名为WithSubscription。

import DataSource from "../DataSource"let withSubscription = (WrappedComponent, selectData) => { // ……返回另一个新组件…… return class extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); this.state = { data: selectData(DataSource, props) }; } componentDidMount() { // ……注意订阅数据…… DataSource.addChangeListener(this.handleChange); } componentWillUnmount() { DataSource.removeChangeListener(this.handleChange); } handleChange() { this.setState({ data: selectData(DataSource, this.props) }); } render() { // ……使用最新的数据渲染组件 // 注意此处将已有的props属性传递给原组件 const style = { "marginBottom":"30px" } return( <div style={style}> <div>This is a HOC Component...</div> <WrappedComponent data={this.state.data} {...this.props} /> </div> ); } };}export default withSubscription;

高阶组件既不会修改原组件,也不会使用继承复制原组件的行为。相反,高阶组件是通过将原组件包裹(wrapping)在容器组件(container component)里面的方式来组合(composes) 使用原组件。高阶组件就是一个没有副作用的纯函数。高阶组件接收容器组件的所有props属性以及一个新的 data属性,并将从数据源订阅的数据用 data 属性渲染输出内容。高阶组件并不关心数据是如何以及为什么被使用,而被包裹组件也不关心数据来自何处。

高阶组件使用

./pages/index.jsimport React from "react"import HOCList from "../components/HOCList";import CommentList from "../components/CommentList";import BlogPost from "../components/BlogPost";import withSubscription from "../components/WithSubscription/index"const CommentListWithSubscription = withSubscription( CommentList, (DataSource) => DataSource.getComments());const BlogPostWithSubscription = withSubscription( BlogPost, (DataSource, props) => DataSource.getBlogPost(props.id));export default class extends React.Component { constructor(props) { super(props); } componentDidMount() { } render() { const style = { width:"100%", "text-align": "center", title:{ color:"red" } } return ( <div style={style}> <h1 style={style.title}>hello hoc</h1> <CommentListWithSubscription /> <BlogPostWithSubscription /> </div> ); }}

CommentListWithSubscription的第一个参数是包裹组件(wrapped component),第二个参数会从 DataSource和当前props即高阶组件的props属性中检索需要的数据。当 CommentListWithSubscription 和 BlogPostWithSubscription 渲染时, 会向CommentList 和 BlogPost 传递一个 data props属性,该 data属性的数据包含了从 DataSource 检索的最新数据。

官网的示例代码不完全,为了更好地看到运行结果,对代码做一些修改:

另外创建数据源DataSource:

./components/DataSource.jslet DataSource = { getComments: () => { return [ "comment1", "comment2", "comment3" ] }, getBlogPost: () => { return "BlogPost Contents"; }, addChangeListener: () => { console.log("addChangeListener") }, removeChangeListener: () => { console.log("removeChangeListener") },}export default DataSource;两个被包裹组件只负责对数据源的展示:

//.components/BlogPost/index.jsimport React from "react"import { Input,Button } from "antd"const { TextArea } = Input;export default class extends React.Component { render() { return ( <div> <TextArea value={this.props.data} /> </div> ); }}

//.components/BlogPCommentListst/index.jsimport React from "react"export default class extends React.Component { render() { return ( <div> {this.props.data.map((value) => ( <div comment={value} key={value} >{value}</div> ))} </div> ); }}

运行结果:http://localhost:3000/

完整源码地址:https://github.com/wuhuaranran/myHOC

文章评论

Top