翻译 | React AJAX 最佳实践

1,832 阅读6分钟

作者:张捷 (沪江Web前端开发工程师)

本文原创翻译,有不当的地方欢迎指出。转载请指明出处。

当你问起有关AJAX与React时,老司机们首先就会告诉你:React其实是个没有网络请求/AJAX功能的view库。这种说法很容易理解,但对于当你仅想让你的React组件从服务器上获取数据时,是没啥帮助的。

事实上,有很多种方法可以满足你的需求。也许你自己也脑洞大开考虑过几个,但一旦走错了方向,那代码可就一团糟了。

好吧,这下你好奇了:到底什么才是正确的、值得首选的方法呢?

答案是……看情况~~~

下面为大家一一介绍我收集的在React里使用AJAX的四个好方法。不过要注意的是,得根据app的大小及复杂度,和你已使用的库和技术来决定该使用哪种方法。

1.根组件(Root Component)方法

这是一种最简单的方法,因此它适用于简单或小型的应用。

通过这种方法,你可以建立单一根组件(父层组件)去分发所有AJAX请求,然后它会把AJAX响应数据存储进state里,以props方式传递到子组件。可以参考下官方教程上的实例

官方教程上的实例

facebook.github.io/react/tutor…

此实例中的CommentBox组件就是个分发所有AJAX请求的根组件。

不过,我不大喜欢官方教程实例中的一点:它使用了jQuery去发送AJAX请求。

jQuery是个有很多功能的大库,因此仅因AJAX而引入它是没多大意义的。

我推荐使用fetch()这个简单、标准化的JavaScript 网络请求API,它已被Chrome、Firefox浏览器支持,并且可以通过使用fetch polyfill去兼容其他浏览器。如果想要更具体地了解,大家可以参考我的《AJAX库之对比》,也许这对你选择自己的AJAX库有点帮助。

AJAX库之对比

andrewhfarmer.com/ajax-librar…

注意:如果你的项目有着很深的组件树结构(子组件层层嵌套下去),那么就会需要把数据从根组件一层一层传递至子组件,而这个传递数据之路将比较长。

适宜使用root component 方法的场景:

    1、项目组件树比较简单

    2、项目中没有使用Redux或flux

2、容器组件方法(Container Components)

容器组件就是“为展示组件或其它容器组件提供数据和方法的组件”,如果你还没有听过这个概念,建议你可以先阅读下Dan Abramov的有关展示组件和容器组件的文章。

展示组件和容器组件

medium.com/@dan_abramo…

 

容器组件方法与根组件方法很像,不同的是容器组件可以支持多组件与服务器端交互。(根组件方法仅支持通过单一组件与服务器端交互)

容器组件方法是这样工作的:对于每个需要从服务器拿到数据的展示组件来说,需要有个可以发送网络请求的容器组件来把请求到的数据通过props传递给子组件。

举个具体的栗子:你想要展示一个有着name和picture的用户简介。我们该怎么去做呢?接下来,我们一步步来:

1.建立一个展示组件:<UserProfile />, 这个组件可以接收到name 和profileImage 数据。但是这个组件一定不能有任何AJAX请求代码。 2.建立组件<UserProfileContainer /> ,这个组件用来接收urserId .它请求到用户的数据以后通过props传递给刚才创建的组件<UserProfile />。

这样用户简介展示就实现了。容器组件中的AJAX请求将会由简单的AJAX库发送出去,这里我推荐使用fetch()方法

fetch()方法

andrewhfarmer.com/ajax-librar…

适宜为网络请求使用容器组件方法的场景:    1.项目组件树比较深    2.项目中除了某些组件需要从服务器上获取数据,绝大多数组件是不需要的。    3.项目需要从多端或多个API中获取数据。    4.项目中没有使用Redux或flux. 或者与’异步操作’方法相比,你更喜欢使用容器组件方法来完成请求数据功能。

3.Redux Async Actions

Redux管理数据,而AJAX提供服务器上的数据,因此Redux 应用于处理网络请求。

如果使用Redux,就不要把AJAX放进React组件里面,而是要放进Async Actions里。

Async Actions

redux.js.org/docs/advanc…

这里我还是推荐fetch()方法去处理实际网络请求,幸运地,Redux官方文档上也是使用fetch().文档中已有一个使用Redux、React和fetch()方法的实例

example reddit API.

redux.js.org/docs/advanc…

如果你使用flux,那这个方法也是类似的——在actions中发送网络请求。

适宜使用Redux Async Actions的场景:

    1.项目中正使用着Redux    2.项目中正使用着flux,使用方式也是类似的

4.Relay

通过Relay,你需要使用GraphQL声明React组件需要的数据,然后,Relay会自动下载数据并传递至组件的props中。

Relay

facebook.github.io/relay/

Relay很适用于一个大型应用中,但是对于使用者来说,还是需要比较丰富的前期知识储备的。你需要:

1.学习Relay和GraphQL.

2.使用GraphQL指定React组件的数据需求,而不是使用propTypes来指定

3.准备一台GraphQL服务器

Relay仅意味着要连接GraphQL服务器,因此它不会帮你连接任何第三方API.

目前,Relay仅能连接单一GraphQL服务器,因此,如果你要从多台服务器中获取数据,那Relay方法就不适用了。不过,将来有可能支持连接多台服务器,这个问题已经在github上讨论得热火朝天了。

github上讨论

github.com/facebook/re…

如果你要继续研究Relay方法,那Realy Playground 是个搞清楚它如何工作的好地方。

Realy Playground

facebook.github.io/relay/proto…

适宜使用Relay方法的场景:    1.想要创建一个大型应用而又比较关心Relay设计去解决的问题(https://facebook.github.io/react/blog/2015/05/01/graphql-introduction.html#why-invent-something-new)    2.项目中还没有建立JSON API    3.为项目准备一台GraphQL服务器    4.项目只会连接单一服务器

彩蛋:反模式

如果以上方法都是正确的,那么什么方法是错误的呢?下面我来介绍两种大家尽量要避免使用的方法。

反模式 1:在展示组件中使用AJAX请求

已经用作负责其他功能(如复杂界面渲染)的组件中就不要添加AJAX逻辑了,否则只会违反关注点分离的设计原则。

关注点分离

en.wikipedia.org/wiki/Separa…

反模式2:ReactDOM.render()

你可以使用完全游离于React之外的AJAX逻辑,当数据无论何时更新时,调用ReactDOM.render()来更新页面。

ReactDOM.render()

facebook.github.io/react/docs/…

这个方法也许可以正常运行。将它以反模式方式提出来,是因为我坚信第一种根组件方法虽与其类似,但简洁多了。

结论:

使用React建立的应用都是模块化的,React会成为其中一个模块,AJAX库是另一个模块。而使用Rails和Angular框架的应用,Rails或Angular则不会成为应用中的模块。

原文:http://andrewhfarmer.com/react-ajax-best-practices/