React的组件模式

图片描述

想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!前端

组件是 React 的核心,所以了解如何利用它们对于建立优秀的设计结构相当重要。react

什么是组件

根据 React 官网的介绍,“组件让你能够将 UI 分割成独立的、可重用的部分,并独立管理每一个部分。”git

当你第一次安装 npm install react 时,会获得一件事:组件及其 API。与 JavaScript 函数相似,组件接受名为 “props” 的输入并返回 React 元素,该元素描述(声明)用户界面(UI)的外观。这就是为何 React 被称为声明性 API,由于你告诉它你但愿 UI 是什么样子的,而 React 负责其他的工做。github

能够把声明式想像成当打的去一个目的地时,只须要告诉司机去哪里,他就会开车把你送到那里。命令式编程正好相反—,你得本身驾车到那里。npm

组件的 API

当安装 React 后,即可以使用 React 提供的 API,基本能够分红 5 种。编程

图片描述

  • render
  • state
  • props
  • context
  • lifecycle events

尽管一个组件可使用上述全部 API,但一个组件一般用到只有少数几个 API,而其余组件则只使用其余 API。redux

能够对组件使用不一样的 API 对组件进行划分,分为 有状态(stateful)无状态(stateless) 两种组件。segmentfault

  • 有状态组件一般使用 API: render, state 和生命周期相关事件。
  • 无状态组件一般使用 API: render, props 和 context。

图片描述

以上就是咱们为佬要介绍 组件模式 的缘由。组件模式是使用 React 时的最佳实践,最初引入组件模式是为了将数据逻辑和 UI 表现层进行分离。经过在组件之间划分职责,您以建立更多可重用的、内聚的组件,这些组件可用于组合复杂的 UI,这在构建可扩展的应用程序时尤为重要。react-router

组件模式

一般组件模式有如下几种:less

  • Container (容器组件)
  • Presentational (展现组件)
  • Higher order components (高级组件)
  • Render callback (渲染回调)

Container (容器组件)

“容器组件就是取数据,而后渲染子组件而已” —— Jason Bonta

蓝色表明容器组件,灰色表明展现组件

容器组件是你的数据或逻辑层并利用 stateful API,使用生命周期事件,你能够链接 state
redux 或者 Fluxstorage 中,并将数据和回调做为 props 传递给子组件。

在容器组件的 render 方法中,你可使用 展现组件 来渲染具体的样式。为了可以访问到全部状态 API,容器组件必须使用 class 的方式声明,而不是使用函数式方法声明。

在下面的示例中,咱们有一个名为 Greeting 的类组件,它具备状态,生命周期事件componentDidMount()render 方法。

class Greeting extends React.Component {
  constructor() {
    super();
    this.state = {
      name: "",
    };
  }

  componentDidMount() {
    // AJAX
    this.setState(() => {
      return {
        name: "William",
      };
    });
  }

  render() {
    return (
      <div>
        <h1>Hello! {this.state.name}</h1>
      </div>
    );
  }
}

此时,该组件是一个有状态类组件,为了使 Greeting 成为一个容器组件,咱们能够将 UI 拆分为一个 展现组件,将在下面进行说明。

展现组件

展现组件 使用 propsrendercontext (无状态API),而且因为不须要使用生命周期相关 Api,可使用纯函数来简化表述它们:

const GreetingCard = (props) => {
  return (
    <div>
      <h1>Hello! {props.name}</h1>
    </div>
  )
}

展现组件 仅从 props 接收数据和回调,这些数据和回调能够由其容器组件(父组件)提供。

蓝色是展现组件,灰色是容器组件

容器组件和展现组件各自将数据/逻辑和展现部分封装到各自的组件中:

const GreetingCard = (props) => {
  return (
    <div>
      <h1>{props.name}</h1>
    </div>
  )
}

class Greeting extends React.Component {
  constructor() {
    super();
    this.state = {
      name: "",
    };
  }

  componentDidMount() {
    // AJAX
    this.setState(() => {
      return {
        name: "William",
      };
    });
  }

  render() {
    return (
      <div>
       <GreetingCard name={this.state.name} />
      </div>
    );
  }
}

如你所见,已经将 Greeting 组件中展现相关的部分移动到了它本身的函数式展现组件中。固然,这是一个很是简单的例子——对于更复杂的应用程序,这也是最基本的。

高阶组件

高阶组件是一种函数,它接受一个组件做为参数,而后返回一个新的组件。

这是一种能够对输入组件的 props 进行修改(增删改查)而后返回全新的修改后的组件强大模式,想一想 react-router-v4redux 。用了 react-router-v4 后,你可使用 withRouter() 来继承以 props 形式传递给组件的各类方法。一样,用了redux,就可使用 connect({})() 方法来将展现组件和 store 中的数据进行链接。

图片高阶组件用虚线表示,它是一种返回组件的函数

代码演示:

import {withRouter} from 'react-router-dom';

class App extends React.Component {
  constructor() {
    super();
    this.state = {path: ''}
  }
  
  componentDidMount() {
    let pathName = this.props.location.pathname;
    this.setState(() => {
      return {
        path: pathName,
      }
    })
  }
  
  render() {
    return (
      <div>
        <h1>Hi! I'm being rendered at: {this.state.path}</h1>
      </div>
    )
  }
}

export default withRouter(App);

导出组件时,使用用 react-router-v4withRouter()方法封装它。 在 组件 App 的生命周期事件 componentDidMount() 方法中,咱们使用this.props.location.pathname 提供的值来更新 state。 因为咱们使用了 withRouter 高阶组件,咱们能够直接访问 this.props.locationlocation,而不须要直接将 location 做为 props 直接传入,很是方便。

渲染回调

与高阶组件相似,渲染回调或渲染 props 被用于共享或重用组件逻辑。虽然许多开发人员倾向于使用 高阶组件 的可重用逻辑,可是使用 渲染回调 仍然有一些很是好的理由和优点——这是在 Michael Jackson 的“永不写另外一个高阶组件”中获得了最好的解释。简而言之,渲染回调减小了命名空间冲突,并更好的说明了逻辑来源。

蓝色虚线表示渲染回调

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
  }

  increment = () => {
    this.setState(prevState => {
      return {
        count: prevState.count + 1,
      };
    });
  };

  render() {
    return (
      <div onClick={this.increment}>{this.props.children(this.state)}</div>
    );
  }
}

class App extends React.Component {
  render() {
    return (
      <Counter>
        {state => (
          <div>
            <h1>The count is: {state.count}</h1>
          </div>
        )}
      </Counter>
    );
  }
}

Counter 类中,在 render 方法中嵌入 this.props.children 并将 this.state 做为参数。在 App 类中,咱们能够将咱们组件封装在 Counter 组件中,所以我能够操做 Counter 组件内的逻辑。

Counter 组件的本质是暴露了 children 这个外部属性,将 children 具体的渲染细节交个 Counter 的使用者,使用的时候只须要将组件传入到 Counterchildren 中,固然可使用其余参数,若是 children 不够的话。

代码部署后可能存在的BUG无法实时知道,过后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给你们推荐一个好用的BUG监控工具 Fundebug

原文:

https://medium.com/teamsubcha...

你的点赞是我持续分享好东西的动力,欢迎点赞!

欢迎加入前端你们庭,里面会常常分享一些技术资源。

clipboard.png

相关文章
相关标签/搜索