简评:组件(component)是 React 的核心,了解它们有助于构建好的设计结构。

什么是组件(component)

组件运行你将 UI 拆分为独立的可重用的部分。和 JavaScript 函数类似,组件接收名为 props 的输入并返回 React 元素,它描述(声明)用户界面应该是什么样子的。这就是 React 被称为声明性 API 的原因,你只需要声明你希望得到的 UI ,之后 React 负责具体的细节。

组件 API

当安装 React 后,便可以使用 React 提供的 API,基本可以分成 5 种。

  • render
  • state
  • props
  • context
  • lifecycle events

虽然组件可以使用所有的 API,但是通常一个组件只使用部分的 API,我们可以对使用不同 API 的组件进行细分,分成有状态(stateful) 和无状态(stateless) 两种组件。

  • 有状态组件使用(render,state 和 生命周期相关事件)
  • 无状态组件使用 (render,props 和 context)

这样将数据逻辑和 UI 表现层进行分离,通过组件之间划分职责可以创建更多可重用的组件,在构建可扩展的应用程序时尤为重要。

组件模式

通常组件模式有以下几种:

  • Container
  • Presentational
  • 高阶组件(Higher order components 【HOC’s】)
  • Render callback

container

容器组件(container component )负责获取数据然后渲染部分交给相应的子组件来负责。

容器是你的数据或逻辑层并利用 stateful API,使用生命周期事件你可以连接 state 到 redux 或 flux 的 storage 中。在容器组件的 render 方法中,你可以使用 Presentational 组件来渲染具体的样式。

注意:由于容器组件需要使用 stateful api ,所以容器组件需要定义成类而不能是一个纯函数。

我们来定义一个 组件 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 进行改进,将其分离成容器组件(container component)和展示组件(presentational component)。

Presentational

Presentational components 使用 props,render,和 context (stateless API's) ,并且由于不需要使用生命周期相关api,我们可以使用纯函数来简化表述它们:

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

Presentational components 只从 props 获取数据和回调函数,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>
);
}
}

高阶组件(Higher order components【HOC’s】)

高阶组件是一个接收一个组件作为参数然后返回全新组件的函数。

这是一种强大的模式,我们可以对输入组件的 props 进行修改(增删改查)然后返回全新的修改后的组件,例如 react-router-v4 的 withRouter() 方法可以包装任何自定义组件,将 react-router 的 history,location,match 三个对象传入,不需要一级级传入。例如 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-v4 的 withRouter() 来封装它。在 componentDidMount 这个生命周期中,我们使用 this.props.location.pathname 来更新我们的 state,由于我们使用了 withRouter 高阶组件,我们可以直接访问 this.props.locationlocation,而不需要直接将 location 作为 props 直接传入,非常方便。

Render callbacks

与高阶组件类似,render callbacks 或 render props 可以用来重用逻辑。

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.childrn 并将 this.state 作为参数。在 App 类下面,我们可以将我们组件包装在 Counter 组件中。

Counter 组件的本质是暴露了 children 这个外部属性,将 children 具体的渲染细节交个 Counter 的使用者,使用的时候只需要将组件传入到 Counter 的 children 中,当然可以使用其他参数,如果 children 不够的话。例如实现一个聊天列表每条消息有头像和消息内容,具体头像是圆是方,具体消息内容是文字是图片,都交给了外部使用者。

原文:React component patterns

React 组件模式的更多相关文章

  1. React的组件模式

    组件是 React 的核心,因此了解如何利用它们对于创建优秀的设计结构至关重要. 什么是组件 根据 React 官网的介绍,"组件让你可以将 UI 分割成独立的.可重用的部分,并独立管理每个 ...

  2. jquery插件模式开发和react组件开发之间的异同

    jquery插件模式开发和react组件开发之间的异同

  3. react 反模式——不使用jsx动态显示异步组件

    前言: react反模式 (anti-patterns)指的是违背react思想(flux)的coding方式. 本文在 App 组件中,通过 Model.show 动态显示 Model 组件,通过 ...

  4. 使用reflux进行react组件之间的通信

    前言 组件之间为什么要通信?因为有依赖. 那么,作为React组件,怎么通信? React官网说, 进行 父-子 通信,可以直接pass props. 进行 子-父 通信,往父组件传给子组件的函数注入 ...

  5. React 组件开发初探

    react.js 在线地址:http://slides.com/yueyao/deck/#/ COMPONENT JSX 预编译语言, 一个基于ECMAscript 的xml-link 的语法扩展,最 ...

  6. 总结 React 组件的三种写法 及最佳实践 [涨经验]

    React 专注于 view 层,组件化则是 React 的基础,也是其核心理念之一,一个完整的应用将由一个个独立的组件拼装而成. 截至目前 React 已经更新到 v15.4.2,由于 ES6 的普 ...

  7. react 组件的生命周期

    组件的生命周期 过程 装载(Mounting) :组件被插入到 DOM 中: 更新(Updating) :组件重新渲染以更新 DOM: 卸载(Unmounting) :组件从 DOM 中移除. 过程 ...

  8. 深入React组件生命周期

    上篇博文使用React开发的一些注意要点对React开发的一些重点进行了简单的罗列总结,虽然也提到了React生命周期,但只略微小结,在此单独写篇React生命周期的总结. 在组件的整个生命周期中,随 ...

  9. 如何优雅的设计 React 组件

    作者:晓冬 本文原创,转载请注明作者及出处 如今的 Web 前端已被 React.Vue 和 Angular 三分天下,一统江山十几年的 jQuery 显然已经很难满足现在的开发模式.那么,为什么大家 ...

随机推荐

  1. spring boot 2

    服务端验证: // 1.修改实体 @Min(value = 18,message = "必须大于18岁") private int age; // 2.修改add方法 @PostM ...

  2. 【转】字符串匹配的KMP算法:移动位数 = 已匹配 - 部分匹配值(共有长度)

    计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"? 许多算 ...

  3. __next__和__iter__实现迭代器协议

    ---恢复内容开始--- #_*_coding:utf-8_*_ __author__ = 'Linhaifeng' class Foo: def __init__(self,x): self.x=x ...

  4. struts,hibernate,spring配置时问题汇总及解决办法

    1.java.lang.NoClassDefFoundError: org/objectweb/asm/ClassVisitor 缺少asm-3.3.jar 2.java.lang.NoClassDe ...

  5. 【分享】Java后台开发精选知识图谱

    地址 引言: 学习一个新的技术时,其实不在于跟着某个教程敲出了几行.几百行代码,这样你最多只能知其然而不知其所以然,进步缓慢且深度有限,最重要的是一开始就对整个学习路线有宏观.简洁的认识,确定大的学习 ...

  6. POJ 2778 DNA Sequence (AC自动机+DP+矩阵)

    题意:给定一些串,然后让你构造出一个长度为 m 的串,并且不包含以上串,问你有多少个. 析:很明显,如果 m 小的话 ,直接可以用DP来解决,但是 m 太大了,我们可以认为是在AC自动机图中,根据离散 ...

  7. 何时使用[self release]

    这样的语句   [self release]; 乍看上去让人很困惑. 从release方法本身的作用上来说,就是给self的引用技术减一,就像release对其他对象所做的一样. 一般来说,唯一用到, ...

  8. 如何学习C++? C++ Primer第三版中文版

    C++只是一门工具,要在实际项目中才能感受到它的伟大.是慢慢积累的(任何知识都是,冰冻三尺非一日之寒),它的思想是慢慢领悟的. 知道它的语法不代表你会用,你会用不代表你就会建造起高水平的作品,这是一个 ...

  9. POJ1273&&Hdu1532 Drainage Ditches(最大流dinic) 2017-02-11 16:28 54人阅读 评论(0) 收藏

    Drainage Ditches Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  10. Ubuntu的常识使用了解3

    打包与压缩