React 组件模式-有状态组件 x 无状态组件、容器组件 x 展示组件、高阶组件 x 渲染回调(函数作为子组件)

栏目: 服务器 · 发布时间: 6年前

内容简介:有状态组件 x 无状态组件、容器组件 x 展示组件、高阶组件 x 渲染回调(函数作为子组件)自从我使用 React(Facebook,一个使用 JavaScript 构建用户界面的库)以来已经有一段时间了 – 当我刚刚开始时,我希望我知道一些概念。本文试图总结我迄今为止所学到的一些模式 – 同时希望对于即将进入这个令人敬畏的基于组件的世界的开发人员也有所帮助。就像有状态和无状态Web服务一样,React 组件也可以在应用程序使用期间保持和操作状态(stateful) , 或者只是一个简单的组件,它接受输入
React 组件模式-有状态组件 x 无状态组件、容器组件 x 展示组件、高阶组件 x 渲染回调(函数作为子组件)

有状态组件 x 无状态组件、容器组件 x 展示组件、高阶组件 x 渲染回调(函数作为子组件)

自从我使用 React(Facebook,一个使用 JavaScript 构建用户界面的库)以来已经有一段时间了 – 当我刚刚开始时,我希望我知道一些概念。本文试图总结我迄今为止所学到的一些模式 – 同时希望对于即将进入这个令人敬畏的基于组件的世界的开发人员也有所帮助。

有状态(stateful)组件 和 无状态(stateless)组件

就像有状态和无状态Web服务一样,React 组件也可以在应用程序使用期间保持和操作状态(stateful) , 或者只是一个简单的组件,它接受输入 props 并返回要显示的内容(stateless)。

一个简单的 无状态(stateless) 按钮组件,仅依赖于 props(属性) ,这也称为函数式组件:

const Button = props =>
  <button onClick={props.onClick}>
    {props.text}
  </button>

下面者是一个 有状态(stateful) 的计数器组件 ButtonCounter (使用了 Button 组件):

class ButtonCounter extends React.Component {
  constructor() {
    super()
    this.state = { clicks: 0 }
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick() {
    this.setState({ clicks: this.state.clicks + 1 })
  }

  render() {
    return (
      <Button
        onClick={this.handleClick}
        text={`You've clicked me ${this.state.clicks} times!`}
      />
    )
  }
}

注意:只有 类(class)组件才会有 state(状态),函数式组件不会有有 state(状态)。 关于函数式组件和类组件的说明请参考官方文档

如您所见,第二个组件的 constructor(构造函数) 包含一个组件 state(状态),而第一个组件是一个简单的组件,通过 props(属性) 渲染文本。有状态组件和无状态组件的划分看起来非常简单,但可以使 Button 组件具有高度可重用性。

容器(Container) 组件 和 展示(Presentational) 组件

在处理外部数据时,我们可以将组件划分为这两个新类别。 容器(Container) 组件负责访问数据,它常常是超出了React范畴的,例如使用 Redux 或 Relay 进行了绑定。对比而言,虽然 展示(Presentational) 组件与应用程序的其余部分没有依赖关系,它只取决于其自身的 state(状态) 或 接收到的 props(属性) 。让我们来看看将用户列表作为 展示组件 的示例:

const UserList = props =>
  <ul>
    {props.users.map(u => (
      <li>{u.name} — {u.age} years old</li>
    ))}
  </ul>

可以使用我们的容器(Container)组件更新这个列表组件 UserList

class UserListContainer extends React.Component {
  constructor() {
    super()
    this.state = { users: [] }
  }

  componentDidMount() {
    fetchUsers(users => this.setState({ users }))
  }

  render() {
    return <UserList users={this.state.users} />
  }
}

这种方法将数据获取与渲染分开,并使 UserList 可重用。如果你想进一步了解这种模式,来自 Dan Abramov 的精彩文章 作了解释更详细的解释。

高阶组件(Higher order components , HOC )

当您想要重用组件逻辑时,高阶组件(简称HOC)非常有用。 它们是 JavaScript 函数,它将组件作为参数并返回一个新组件。

假设你需要构建一个可扩展的菜单组件,当用户点击它时会显示一些子内容。 因此,您可以简单地创建一个通用的HOC来处理它,而不是控制其父组件上的 state(状态) :

function makeToggleable(Clickable) {
  return class extends React.Component {
    constructor() {
      super()
      this.toggle = this.toggle.bind(this)
      this.state = { show: false }
    }

    toggle() {
      this.setState(prevState => ({ show: !prevState.show }))
    }

    render() {
      return (
        <div>
          <Clickable
            {...this.props}
            onClick={this.toggle}
          />
          {this.state.show && this.props.children}
        </div>
      )
    }
  }
}

这种方法允许我们使用 JavaScript 装饰器语法,将我们的逻辑应用于我们的 ToggleableMenu 组件:

@makeToggleable
class ToggleableMenu extends React.Component {
  render() {
    return (
      <div onClick={this.props.onClick}>
        <h1>{this.props.title}</h1>
      </div>
    )
  }
}

现在我们可以将任何子节点传递给 ToggleableMenu 组件:

class Menu extends React.Component {
  render() {
    return (
      <div>
        <ToggleableMenu title="First Menu">
          <p>Some content</p>
        </ToggleableMenu>
        <ToggleableMenu title="Second Menu">
          <p>Another content</p>
        </ToggleableMenu>
        <ToggleableMenu title="Third Menu">
          <p>More content</p>
        </ToggleableMenu>
      </div>
    )
  }
}

如果你熟悉 Redux 的 connect 函数或者 React Router 的 withRouter 函数,那么你已经使用过高阶组件了。

渲染回调(Render Callbacks)

愚人码头注:这种模式以前也叫 函数作为子组件(Function as Child Components) , 现在最新的叫法为:渲染属性(Render Props),请参阅官方文档。

使组件逻辑可重用的另一个好方法是将组件子项转换为函数 – 这就是为什么将渲染回调也称为函数作为子组件。 我们可以举一个例子,使用渲染回调模式重写上面的 Menu 组件:

class Toggleable extends React.Component {
  constructor() {
    super()
    this.toggle = this.toggle.bind(this)
    this.state = { show: false }
  }

  toggle() {
    this.setState(prevState => ({ show: !prevState.show }))
  }

  render() {
    return this.props.children(this.state.show, this.toggle)
  }
}

现在我们可以传递一个函数作为我们 Toggleable 组件子项:

<Toggleable>
  {(show, onClick) => (
    <div>
      <div onClick={onClick}>
        <h1>First Menu</h1>
      </div>
      {show ?
        <p>Some content</p>
        : null
      }
    </div>
  )}
</Toggleable>

上面的代码已经使用了一个函数作为子代,但是,如果我们想要像我们在 HOC 示例(多个菜单)中那样重用它,我们可以简单地创建一个使用 Toggleable 逻辑的新组件:

const ToggleableMenu = props =>
  
    {(show, onClick) => (

{props.title}

{show && props.children}

)}

ToggleableMenu
class Menu extends React.Component {
  render() {
    return (
      <div>
        <ToggleableMenu title="First Menu">
          <p>Some content</p>
        </ToggleableMenu>
        <ToggleableMenu title="Second Menu">
          <p>Another content</p>
        </ToggleableMenu>
        <ToggleableMenu title="Third Menu">
          <p>More content</p>
        </ToggleableMenu>
      </div>
    )
  }
}

我们的 Menu 组件看起来与我们的 HOC 示例完全相同!

当我们想要改变渲染内容而不管状态操作时,这种方法非常有用:正如您所看到的,我们将渲染逻辑移到了 ToggleableMenu 子函数中,但 状态(state) 逻辑依然在我们的 Toggleable 组件进行维护。

了解更多

上面的例子只是你可以在你的 React 代码中使用的一些模式的基础知识,如果你真的想深入研究这些主题,我建议你看看这些有用的东西:

以上的一些例子仅仅是 React 设计模式的基础知识。如果你想更加深入地了解关于 React 设计模式的话题,以下是一些非常好的学习资料,值得一看:

原文链接: https://levelup.gitconnected.com/react-component-patterns-ab1f09be2c82


以上所述就是小编给大家介绍的《React 组件模式-有状态组件 x 无状态组件、容器组件 x 展示组件、高阶组件 x 渲染回调(函数作为子组件)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

菜鸟侦探挑战数据分析

菜鸟侦探挑战数据分析

[日] 石田基广 / 支鹏浩 / 人民邮电出版社 / 2017-1 / 42

本书以小说的形式展开,讲述了主人公俵太从大学文科专业毕业后进入征信所,从零开始学习数据分析的故事。书中以主人公就职的征信所所在的商业街为舞台,选取贴近生活的案例,将平均值、t检验、卡方检验、相关、回归分析、文本挖掘以及时间序列分析等数据分析的基础知识融入到了生动有趣的侦探故事中,讲解由浅入深、寓教于乐,没有深奥的理论和晦涩的术语,同时提供了大量实际数据,使用免费自由软件RStudio引领读者进一步......一起来看看 《菜鸟侦探挑战数据分析》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

在线进制转换器
在线进制转换器

各进制数互转换器

SHA 加密
SHA 加密

SHA 加密工具