使用react开发的优秀实践

使用react开发的优秀实践

November 15, 2017
Web, Javascript, React

如果想用react开发功能丰富,易于代码管理,易于扩展维护的项目,我们最好使用react的一整个体系。当然你单独使用react的部分也是可以的,写一些简单的应用也非常方便,没有必要把这个体系用上。

这篇文章作为入门的一篇略深一些的介绍,在全面学习之前我们至少要知道我们学的每个部分是做什么,为什么要在这里用这个。所以本文不讲一些代码的细节,而是从整体上把握这个技术栈,帮助你快速理解整个体系。

总结 #

一个比较好的实践是使用: react + redux + router, 来实现复杂的应用。 其中, react 承担了前端渲染控制的功能,redux承担了数据流转的控制功能,router则实现了路由控制的功能。

这三项,基本上可以保证我们做出的项目,结构清晰,易于维护。 在初学这写东西的时候,可能会觉得比较痛苦,因为你需要记住太多的东西和条条框框来开发,这好像限制了你的自由发挥,但是对于一个大型应用来说,或者即便是小应用,没有清晰的结构,就连你自己可能都看不懂自己的代码,后期维护的时候就基本上没有多少好体验了。

真正优秀的作品,都是在严格的限制下完成的,因为人的思维不应该去思考那些复杂的页面组成的逻辑关系,而是在实现自己的业务逻辑和计算算法上,那些结构,按照一个科学的方式来做就好。而react正是提供了这样一个科学的流程和方式。

react #

总的来说,在前端渲染方面,react非常出众, 一般我们将前端渲染的部分交给react来做。 react使用虚拟DOM的方式,来管理渲染。并且将一个页面分成多个组件进行管理,我们一般将组件按功能分开。当页面发生变化的时候,由react来决定哪里需要渲染,哪里不动,react来操纵浏览器的渲染。 与jQuery相比,更进一步, jQuery是将浏览器的一些操作封装出来,提供一组新的调用函数。但是react已经将浏览器的相关接口完全封装,并且屏蔽在react内部,提供了一种更自然和智能的方式来满足我们的需求。我们直接和react打交道,剩余的事情由react去和浏览器做。

react这个框架可以运行在浏览器端,也可以运行在服务器端, 我们称之为Universal渲染,这里的服务器端,就是Nodejs的平台了。我用的基本上都是浏览器端运行。只要将react的脚本发送到浏览器进行执行就可以了。 初的渲染是后端的事情,有了ajax后前端也可以进行渲染了。但是前端渲染会有个问题,就是搜索引擎不友好,因为搜索引擎并不会去跟js代码交互,只会爬取静态页面,所以使用后端渲染十分重要。这关乎你的网站被检索到的可能性。

基本构造 #

react的逻辑很简单,一切都是组件。一个页面是由多个组件堆砌而成,每个组件之间互相隔离,仅通过数据交互,而数据交互的接口是固定的。所以对于一个组件内部来说,与外界是完全隔离的。 一个组件包括,样式和数据。数据我们通过请求服务器去获得。 每个组件通过提供一个render函数来返回这个组件,这个render函数只能返回一个元素。如果有多个元素需要被包起来成为一个元素返回。 组件之间可以是嵌套关系,这个和类的概念有点像,在一个类中可以包含另一个类作为自己的成员。也就是方便我们做组件封装,功能划分。

当我们写完一个react应用后,可以通过npm start的方式启动起来,当我们在浏览器访问对应的地址时,默认访问index.js, 所以我们的应用最终在这里组织起来。

ES6 & Javascript & JSX #

在写应用的时候,我们使用JSX 语法来写,JSX以ES6为基础,react提供了JSX解释器。在写完以后,JSX语法的代码会被编译成JS代码,最终在浏览器中运行的是Javascript的代码,关于webpack等工具,我暂时没有去学习,因为react提供了一个创建react应用的脚本,能够一键创建好这些配置文件,所以我就暂时直接使用了。

npm install --global create-react-app

这个命令就可以安装这个脚本,然后我们执行: create-react-app myapp, 就可以创建一个文件夹, 里面已经配置了一个简单的react应用。 然后我们进入这个文件夹,使用npm start就可以启动服务。 start的过程中,代码就会被编译,并打包成webpack中配置的打包形式。

如果此时我们改变代码,这个页面会动态更新。

react 原生的数据控制 #

在react中,数据主要有三个载体,分别是state、prop、context。其中state是组件内部状态数据,prop用于层层传递,context可以跨层传递。

react要实现各个组件独立,并且具有统一的结构,最重要的就是控制数据。在JS这种弱类型的语言中,这一点很好实现,重点就是设计一个接口形式。 react中的组件,都有两个变量,一个是prop, 一个是state。 其中,state是描述组件内部数据的,prop是对外的接口。也就是说,别人传过来的数据,会存在prop中。同时,prop是不可变的,组件自己不能更改prop的值, 只能改变state的值。

这种数据控制的方式,比较原始,从接口统一的角度来看挺好的,也符合基本的思维方式。 但是这种控制方式也存在很多问题,不用去深究这个框架的细节,我们也可以提出很多问题:

  1. 每个组件之间的数据冗余问题,很多数据统计的模块,该怎么存储数据?

复制一份出来?当要更改数据的时候,是不是还要传参给另一个组件通知他改变数据?

因此这样的数据控制肯定会让程序员自己想办法去解决,这样的解决方式很多,所以就会出现大家都用react,但是写出来的东西互相看不太懂。redux就是在这样的情况下,提供了一个统一的方式。

redux #

redux 对于数据做了如下的限制:

  1. 数据源唯一
  2. 状态只读
  3. 数据改变只能通过纯函数完成

数据源唯一 唯一的数据源,是指所有的数据都存在一个地方Store,由redux做分发,这个数据呈树形分布。 状态只读 状态不能被更改,你需要有个接口,来返回新的数据,redux会自己将数据覆盖上去。 只能通过纯函数该变数据 所谓的纯函数就是指函数的输出完全取决于输入,没有其他的因素。

在redux的限制下,在我们的流程中,需要多几个部分,来实现这个流程。

Store #

这就是存放数据的地方,这是一个类。 其是数据中心,同样,也应该是各个部分联系的中,应用的变化,就体现在数据的变化上,所以store将其余的部分连接在一起了。

一个Store中,定义了能够更新其数据的reducer,数据的初始值, 还有一些中间件。

在每个组件中, 我们都可以通过dispatch函数,来触发相应的reducer去更新数据。当数据被更新的时候,Store会自动通知相应的组件去更新页面。

action #

这是一个动作,准确来说,用来描述一个动作。一个action返回一个数据集, 这些数据描述了一个动作,随后这个动作会被分发给对应的reducer去产生新的数据。这样新的数据就会被redux得到并更新原有的数据。

每个action都有一个字段叫type, 一般是个字符串,用来区分不同的action,同时其也是reducer针对不同action做不同操作的标志。action中定义的数据,我们可以理解为前端产生的数据,然后作为参数传给reducer。

reducer #

同时传给reducer的还有当前该组件中的state。这两个参数作为输入,返回新的state作为输出。这就是reducer的作用。

react 和redux #

上面讲的是每个各自的一些东西,二者并不是必须同时使用的,都是可以分开使用的,redux只是一个数据控制方式,react只是一种前端渲染的方式。二者都可以被替代。

在我们结合使用的过程中,react主要负责的就是渲染,redux就是负责组织数据,我们一般用的是react-redux。 这是专为react封装的一个redux库。

router #

路由一样也可以与上面二者结合,可能更独立一些,因为router是作为一种组件的角色在其中出现。在其内部定义了路由匹配规则,如果你知道django的路由规则,router与之是一样的。

真的总结 #

学习框架技术,在一定意义上,是学习一种思维方式,学会了思维的方式,剩余的就简单了。 接下来会写一些具体的技术细节, 以及各个库之间的联系,配合使用等。

redux在后来的实践中太过繁琐,逐渐被mobx取代。