因为近期在涉及到封装组件的时候遇到了一些问题,因而我认真地了解了一下react封装组件过程当中应该要涉及和思考到的一些问题,写了下来。(如下主要是针对UI组件,因为水平有限不保证内容正确性,仅仅是一些我的的思考)css
组件能够将UI切分红一些的独立的、可复用的部件,这样就只需专一于构建每个单独的部件。node
所谓组件,即封装起来的具备独立功能的UI部件。react
在 React 中,一切皆是组件,所以理解组件的工做流与核心尤其重要。es6
且react中有多种建立组件的方式和各类各样的组件概念,所以在设计组件的时候应该使用哪一种组件的建立方式且应该设计一个怎样的组件都值得深刻思考。数组
咱们常常谈一个设计良好的系统应该是高内聚低耦合的,那么其实我认为一个好的组件也应该是具备高内聚低耦合的特性。bash
由于低耦合会带来如下的好处:异步
而高耦合的组件间会很容易出现一个问题,
就是没法或者很艰难去修改一个大量依赖其余组件的组件,
甚至只是改一个用来传递数据的字段都会致使大量的修改。函数
一个封装良好的组件应该是要隐藏其内部结构的,并经过一组 props来提供控制其行为的途径。性能
隐藏内部结构是必须的。内部结构或实现细节不该该能被其余组件知道或关联。测试
React 组件能够是函数式的,也能够是基于类的,能够定义实例方法、设置 refs、维护 state或是使用生命周期方法。而这些实现细节被封装在组件自身中,其余组件不该该窥见其中的任何细节。
基于此特色来设计的组件对其余组件的依赖是极低的,带来的是低耦合的特色和好处。
我认为组件应该要符合单一职责原则,
一个组件应该尽可能只负责一件事情,而且把这件事情作好,
由于我以为一个组件若是负责处理的事情过多,
在修改其中一件事情的时候颇有可能也会影响到它负责的其余事情,且不利于维护和复用。
在设计一个组件的时候咱们不该该仅限于实现当前的需求,
设计出一个只适用于单一项目的组件,而是应该是一个能够适应大部分同种需求的通用组件。
因此咱们在碰到一个需求的时候应该首先对需求进行抽象,而不是看到设计稿就撸着袖子上。
例如碰到一个轮播图组件的需求的时候,咱们拆分如下这个需求,能够获得:
一个好的组件应该是要像存在魔法同样,只须要极其少数的参数和条件就能够获得指望的效果。就像这个轮播图组件同样,组件应该至少知道的信息有:
其余能够知道也能够不知道的信息能够有:
是否开启自动轮播,默认是开启或者不开启
图片滚动是左右仍是上下,默认是左右
等等 ....................................
(3)这个组件会反馈什么
一个可用的轮播图效果
父组件向封装好的子组件通讯一般是经过props
做为组件的输入,props的值应该最好是js基本类型 (如 string、number、boolean)
可是props能够传入的不只仅只是这些,它但是一个神奇的东西,它能够传入包括:
<Message text="Hello world!" modal={false} />;
复制代码
<Message
data={{
thexAxis: thexAxis ,
lineData : lineData
}}
/>
复制代码
<MoviesList items={['Batman Begins', 'Blade Runner']} />
复制代码
<Message type="text" onChange={handleChange} />
复制代码
function If({ Component, condition }) {
return condition ? <Component /> : null;
}
<If condition={false} component={LazyComponent} />
复制代码
为避免破坏封装,要谨慎对待 props 传递的细节。
父组件对子组件设置 props 时,也不该该暴露自身的结构。
好比,把整个组件实例或 refs 当成 props 传递之类的神奇操做。
访问全局变量是另外一个对封装形成负面影响的问题。
咱们能够经过 proptypes来对传入的数据进行类型限制。
react建立组件有三种方法,分别是:
而目前react推荐ES5方式和ES6方式建立组件的写法中推荐的是ES6的写法,因此这里就不对ES5的写法进行讨论了。
React.Component是以ES6的形式来建立React组件,也是如今React官方推荐的建立组件的方式,
其和React.createClass建立的组件同样,也是建立有状态的组件。
相比React.createClass方式,React.Component带来了诸多语法上的改进
ES6使用import方式替代ES5的require方式来导入模块,其中import { }能够直接从模块中导入变量名,此种写法更加简洁直观。
在ES6的语法规则中,React的组件使用的类继承的方式来实现,去掉了ES5的getInitialState的hook函数,state的初始化则放在constructor构造函数中声明。
React把组件当作一个状态机。经过与用户的交互,实现不一样状态,而后渲染UI,让用户界面和数据保持一致。 组件的任何UI改变,均可以从State的变化中反映出来; State中的全部状态都用于反映UI的变化,不该有多余状态。
React内部是经过调用组件的定义来获取被渲染的节点,而对于不一样的组件定义方式,其获取节点的步骤也不同。以下:
//function方式定义
function Example() {
return <div>this is a div</div>;
}
const node = Example(props);
// 类方式定义
class Example extends React.Component {
render() {
return <div>this is a div</div>;
}
}
const instance = new Example(props);
const node = instance.render();
复制代码
在这里,函数直接调用,类则须要先实例化再去调用实例化对象上的render方法;
若是将类按照普通函数去调用则会报错
由于这方面没有详细去了解过,因此也只是粗浅总结一下其区别:
PureComponent除了提供了一个具备浅比较的shouldComponentUpdate方法,
PureComponent和Component基本上彻底相同。
当组件更新时,若是组件的 props 和 state 都没发生改变, render 方法就不会触发,省去 Virtual DOM 的生成和比对过程,达到提高性能的目的。
若是咱们想用PureComponent去代替Component的时候不须要去作太多的事情,
仅仅是把Component改为PureComponent便可。 可是咱们并不是能够在全部地方都用PureComponent去代替Component,
具体仍是要按照实际状况来选择,由于了解不深就不在此处详谈了。
无状态组件更多的是用来定义模板,接收来自父组件props传递过来的数据,
使用{props.xxx}的表达式把props塞到模板里面。
无状态组件应该保持模板的纯粹性,以便于组件复用,因此一般UI组件应该是无状态组件。
相似于:
var Header = (props) = (
<div>{props.xxx}</div>
);
复制代码
而有状态组件一般是用来处理定义交互逻辑和业务数据
(使用{this.state.xxx}的表达式把业务数据挂载到容器组件的实例上(有状态组件也能够叫作容器组件,无状态组件也能够叫作展现组件),
而后传递props到展现组件,展现组件接收到props,把props塞到模板里面。
相似于:
class Home extends React.Component {
constructor(props) {
super(props);
};
render() {
return (
<Header/>
)
}
}
复制代码
高阶组件给个人感受相似于高阶函数,都是接受一个东西的输入, 而后再给输入的东西添加新的特性做为一个新的东西输出, 看起来相似于装饰器模式的实现。 可是由于目前为止没有写太高阶组件,因此就不在这里讨论了。