react组件的几个模式

前端之家收集整理的这篇文章主要介绍了react组件的几个模式前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
React Component Patterns

有状态组件 x 无状态组件、容器组件 x 展示组件、高阶组件 x Render Callbacks(Function as Child Component)

使用React已经有一段时间了, React——Facebook库,使用JS构建用户界面。本文试图总结迄今为止实践中所学到的一些模式,同时希望能够帮助到即将迈入奇妙地组件世界的开发者。

有状态组件 X 无状态组件

正如web服务有静态和动态之分,React组件也有有状态和无状态的区分。有状态组件--在应用中组件可以拥有自身状态并操纵它;无状态组件--只接收属性进行效果呈现。

一个简单的无状态组件,只受属性控制:

  1. const Button = props => (
  2. <button onClick={props.onClick}>
  3. {props.text}
  4. </button>
  5. );

一个具有计数功能的按钮组件(复用上面Button组件)

  1. class ButtonCounter extends React.Component {
  2. constructor() {
  3. super()
  4. this.state = { clicks: 0 }
  5. this.handleClick = this.handleClick.bind(this)
  6. }
  7.  
  8. handleClick() {
  9. this.setState({ clicks: this.state.clicks + 1 })
  10. }
  11.  
  12. render() {
  13. return (
  14. <Button
  15. onClick={this.handleClick}
  16. text={`You've clicked me ${this.state.clicks} times!`}
  17. />
  18. )
  19. }
  20. }

正如上面两个 Demo 所示,第二个组件的 constructor 具有状态的定义,第一个组件只是单纯地渲染属性文字。有状态组件和无状态组件的划分看起来非常简单,但是它对于组件复用具有重大意义。

容器组件 X 展示组件

当组件需要获取外部数据时,我们又可以将组件划分为两种新的类型。容器组件负责获取数据,它常常是超出了React范畴的,如使用 Redux 或 Relay 进行了绑定。对比而言,展示型组件不依赖于程序其他部分,它只和自身状态或属性有关。下面我们实现一个用户列表的展示组件:

  1. const UserList = props =>
  2. <ul>
  3. {props.users.map(u => (
  4. <li>{u.name} {u.age} years old</li>
  5. ))}
  6. </ul>

容器组件可以用来更新用户列表的展示:

  1. class UserListContainer extends React.Component {
  2. constructor() {
  3. super()
  4. this.state = { users: [] }
  5. }
  6.  
  7. componentDidMount() {
  8. fetchUsers(users => this.setState({ users }))
  9. }
  10.  
  11. render() {
  12. return <UserList users={this.state.users} />
  13. }
  14. }

这种分类将数据获取和渲染的逻辑分开,进而使用户列表组件可以复用。

如果你想了解更多该模式的信息,awesome article from Dan Abramov 对它进行了精确的解释。

高阶组件 -- HOCs

当你想复用组件逻辑时,高阶组件非常有用。高阶组件--是将组件作为参数并返回新组件的 JS 函数

假设你需要构建一个可扩展菜单组件,当用户点击时,它会显示隐藏子组件内容。因此,你可以使用高阶组件来实现:

  1. function makeToggleable(Clickable) {
  2. return class extends React.Component {
  3. constructor() {
  4. super()
  5. this.toggle = this.toggle.bind(this)
  6. this.state = { show: false }
  7. }
  8.  
  9. toggle() {
  10. this.setState(prevState => ({ show: !prevState.show }))
  11. }
  12.  
  13. render() {
  14. return (
  15. <div>
  16. <Clickable
  17. {...this.props}
  18. onClick={this.toggle}
  19. />
  20. {this.state.show && this.props.children}
  21. </div>
  22. )
  23. }
  24. }
  25. }

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

  1. @makeToggleable
  2. class ToggleableMenu extends React.Component {
  3. render() {
  4. return (
  5. <div onClick={this.props.onClick}>
  6. <h1>{this.props.title}</h1>
  7. </div>
  8. )
  9. }
  10. }

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

  1. class Menu extends React.Component {
  2. render() {
  3. return (
  4. <div>
  5. <ToggleableMenu title="First Menu">
  6. <p>Some content</p>
  7. </ToggleableMenu>
  8. <ToggleableMenu title="Second Menu">
  9. <p>Another content</p>
  10. </ToggleableMenu>
  11. <ToggleableMenu title="Third Menu">
  12. <p>More content</p>
  13. </ToggleableMenu>
  14. </div>
  15. )
  16. }
  17. }

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

渲染回调 -- Render Callbacks(Function as Child Components)

另一个比较高端的复用组件逻辑的方法是将函数作为组件的 props.children,该方法也称为Function as Child Components。我们将使用渲染回调来重新实现上面的可扩展Menu:

  1. class Toggleable extends React.Component {
  2. constructor() {
  3. super()
  4. this.toggle = this.toggle.bind(this)
  5. this.state = { show: false }
  6. }
  7.  
  8. toggle() {
  9. this.setState(prevState => ({ show: !prevState.show }))
  10. }
  11.  
  12. render() {
  13. return this.props.children(this.state.show,this.toggle)
  14. }
  15. }

现在,我们可以将函数作为组件的子级进行传递:

  1. <Toggleable>
  2. {(show,onClick) => (
  3. <div>
  4. <div onClick={onClick}>
  5. <h1>{props.title}</h1>
  6. </div>
  7. {show && props.children}
  8. </div>
  9. )}
  10. </Toggleable>

上面的代码已经将一个函数作为子组件,但是,若我们想复用上述逻辑,我们需要创建一个转换逻辑的新组件:

  1. const ToggleableMenu = props =>
  2. <Toggleable>
  3. {(show,onClick) => (
  4. <div>
  5. <div onClick={onClick}>
  6. <h1>{props.title}</h1>
  7. </div>
  8. {show && props.children}
  9. </div>
  10. )}
  11. </Toggleable>

我们使用Render Callbacks实现的可扩展的Menu组件如下:

  1. class Menu extends React.Component {
  2. render() {
  3. return (
  4. <div>
  5. <ToggleableMenu title="First Menu">
  6. <p>Some content</p>
  7. </ToggleableMenu>
  8. <ToggleableMenu title="Second Menu">
  9. <p>Another content</p>
  10. </ToggleableMenu>
  11. <ToggleableMenu title="Third Menu">
  12. <p>More content</p>
  13. </ToggleableMenu>
  14. </div>
  15. )
  16. }
  17. }

Render Callbacks和高阶函数使我们的组件更加灵活,掌握和适应起来具有一定的难度,需要反复学习和消化。


本人能力有限,如有纰漏,请指正。

【开发环境推荐】 Cloud Studio 是基于浏览器的集成式开发环境,支持绝大部分编程语言,包括 HTML5、PHP、Python、Java、Ruby、C/C++、.NET 小程序等等,无需下载安装程序,一键切换开发环境。 Cloud Studio提供了完整的 Linux 环境,并且支持自定义域名指向,动态计算资源调整,可以完成各种应用的开发编译与部署。

猜你在找的React相关文章