常见的组件类型

我们先列举不同的组件类型,最好再对为什么会产生这么多类型的组件以及背后的哲学做说明

这一次我将同时介绍三种 React 开发中非常有用的组件类型, 这三种类型组件常常被组合在一起使用

让我们从最简单的开始

Stateless Component

Stateless Component 又称为 Dump Component ,它的特征和它名字里描述的一样,组件中不保存任何的状态 (state)。它通常只用来展示数据,甚至都不需要生命周期,所以不需要继承 React.Component。Stateless Component 通常只是一个函数而已

function Greeting({ name }) {
    return <p>Hi, {name}</p>
}

它也允许拥有 propTypes 和 defaultProps:

Greeting.propTypes = {
    name: PropTypes.string.isRequired
}
Greeting.defaultProps = {
    name:'Guest'
}

Container Component

如果说 Stateless Component 只是用来渲染数据,那么是谁负责数据加载并且传递给它渲染?Container Component

Contaienr Component 用来加载数据,并且传递数据给其他渲染组件。

接着上面的例子,我们定义一个 Container 用于加载用户信息,然后传递给 <Greeting /> 进行渲染

class UserContainer extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            name: ''
        }
    }
    componentDidMount() {
        axios({
          method:'get',
          url: USER_URL,
        })
        .then(function(response) {
          this.setState({
              name:response.data.name
          })
        });
    }
    render() {
        const {name} = this.state
        if (!name) {
            return null
        }
        return <Greeting name={name} /> 
    }
}

注意这段代码很好的解释了什么是 Container Component,但是其中加载数据的方式并不是好的实践。这个我们在异步加载数据的章节详谈

不难看出,Container Component 的特色是它是功能性的,主要负责加载数据。但这里的加载数据是广义上的:在上面的例子中,加载数据的方式是来自 axios 的异步请求;它也可以来自 react-refetch 的提前抓取;甚至可以选取自 redux store 中。总之它的目的是“取”数据,与渲染无关,也主要为了和渲染隔离开。与渲染无关这个说法并不准确,毕竟它还是会返回元素,但它自己机会不带有渲染业务渲染逻辑

Autonomous Component

读到到这里,你一定有两个疑问:

是否存在一种类型的组件,同时能够加载和渲染数据?

为什么我们要做这样的设计,把数据加载和渲染分离?

我们先回答第一个问题:存在,就是这一节将要介绍的 Autonomous Component, “自治组件”。在互联网上你应该搜索不到这个概念,因为这种组件类型不是公认的定义,而是来自我个人工作中的总结

现实还是需要有复杂的组件参与工作中的,例如 react-select 。它提供强大并且复杂的功能,例如能够根据用户数据异步加载选项,支持多选,支持自定义样式等等。为了维护这些复杂的交互,它的内部一定需要有状态机制来记录用户的输入,过滤已选项,记录用户的配置等等。

组件看上去复杂,但使用起来却异常简单,因为你只需要通过它暴露的接口传递给它配置,表达你的需求即可。你感官上的复杂都封装在背后代码中,关于状态如何新建与更新,数据如何被加载,你都完全接触不到,因为是自治的。

自治不仅仅意味着代码的封装,状态上还需要保证和外界的隔离,保证它的“纯净 (pure) ” (redux 中有两个关于 pure 的概念,一个是 PureComponent ,另一个是 pure function ,这两者在后文中都会提到。这里的 pure 指的是 pure function),即不对“外界”造成变化:例如不反向修改传递给组件的属性,更不能对全局变量造成影响。如果想向外传递属性怎么办?想想原生的 HTML 标签是怎么做的——通过事件处理函数(event handler)

原则上我仍然不建议开发复杂的组件,如果需要,请保证它的自治。如果你不确定如何保证它的自治,请参考原生组件或者第三方组件+

Proxy Component

代理组件就是对原始组件的再一次封装, 使用代理组件的目的主要是为了抽象重复属性

antd 类库中有一个 TextArea 组件,和原生 textarea 功能相同,用于多行输入。在组件上你可以配置 rows 属性用于控制组件高度,还可以配置 { minRows: 2, maxRows: 6 } 用于控制行的最小高度和最大高度。

可组件的默认配置并不符合页面的设计要求,于是我需要自定义 rows 和 autosize 来对组件进行修改。但总不能每一次引用时都一摸一样的设置一遍,于是就可以把相同设置的 TextArea 抽象出来,比如:

function CustomTextArea(props) {
    return <TextArea rows={10} autosize={{minRows: 10, maxRows: 20}} {...props} >
}

这里的 CustomTextArea 就是代理组件,通过它我们定义了一个拥有指定属性的组件

参考资料

​- React Patterns​

results matching ""

    No results matching ""