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

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

内容简介:有状态组件 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 渲染回调(函数作为子组件)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

当下的启蒙

当下的启蒙

[美] 史迪芬·平克 / 侯新智、欧阳明亮、魏薇 / 浙江人民出版社 / 2018-12 / 159.90

[编辑推荐] ● 比尔•盖茨最喜爱的一本书。理查德·道金斯心中的诺贝尔文学奖作品。尤瓦尔•赫拉利2018年最爱的书之一。 ● 当代最伟大思想家史蒂芬·平克全面超越自我的巅峰之作,一部关于人类进步的英雄史诗。 ●《当下的启蒙》用数据和事实揭示出世界的真相:不是黑暗,而是光明;不是丧,而是燃;我们没有退步,而是一直在进步,还将继续进步。用这本书点燃生活的勇气,亲手创造更美好的未来。 ......一起来看看 《当下的启蒙》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

SHA 加密
SHA 加密

SHA 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具