高效地构建具有多个视图的大型 React.js 应用程序

Posted

技术标签:

【中文标题】高效地构建具有多个视图的大型 React.js 应用程序【英文标题】:Efficiently structuring large React.js applications with multiple views 【发布时间】:2015-06-21 08:34:55 【问题描述】:

我有一个带有多个视图的反应应用程序(例如ProfileFollowers)。这些视图中的每一个当前都作为它自己的 React 组件存在,该组件在服务器端和客户端执行。我开始难以理解构建代码的正确方法。

例如,假设 Profile 已加载并且用户点击“查看关注者”。此时,调度员会收到一条消息,上面写着gotoFollowers。在顶层,我们渲染一个全新的 React 组件(即Followers 组件)。不幸的是,FollowerProfile 组件都需要类似的数据(例如会话数据、用户照片、用户名,甚至关注者,因为我们在 Profile 上显示了关注者的 sn-p)。因此,每次用户更改页面时都必须在顶层重新渲染(包括进行 ajax 调用)感觉非常浪费。

我认为我没有正确执行此操作。我应该使用单个父 React 组件吗? (我也看到了问题)我应该如何构建具有许多视图的大型 React 应用程序?

window.render = function (page, id, pushState) 
  var stateURL = '';

  switch (page) 
    case 'Profile':
      stateURL = '/' + id;
      async.parallel(
        profileData: function (callback)  MemberLoader.load(id, callback); ,
        followerData: function (callback)  FollowerLoader.load(id, callback); ,
        ,
        sessionData: function (callback)  Session.get(callback); ,
      , function (err, results) 
        var component = React.createFactory(Profile);
        React.render(component( member: results.profileData, followers: results.followerData, session: results.sessionData ), mountNode);
      );
      break;
    case 'Followers':
      stateURL = '/' + id + '/followers';
      async.parallel(
        profileData: function (callback)  MemberLoader.load(id, callback); ,
        sessionData: function (callback)  Session.get(callback); ,
        followerData: function (callback)  FollowerLoader.load(id, callback); ,
      , function (err, results) 
        var component = React.createFactory(Followers);
        React.render(component( member: results.profileData, followers: results.followerData, session: results.sessionData  ), mountNode);
      );
      break;
  ;

  if (pushState) 
    window.history.pushState( page: page, id: id , null, stateURL);
   else 
    window.history.replaceState( page: page, id: id , null, stateURL);
  

;

Dispatcher.register(function(event) 
  if (event.action === 'gotoProfile') 
    window.render('Profile', event.username, true);
   
  else if (event.action === 'gotoFollowers') 
    window.render('Followers', event.username, false); 
  
);

注意:我们的应用程序在服务器端和客户端都呈现。

【问题讨论】:

【参考方案1】:

要解决多次获取相同数据的问题,您应该查看Promises- 这可以替换您现在正在使用的async 库。

Promises 允许您进行一次异步调用,但即使在调用成功后仍附加回调。您可以维护对 Promise 的引用并稍后在您的应用程序中使用它——而无需检查 Promise 是否已经解决。

我在下面为您整理了一个(未经测试的)示例实现 - 它做了几件事。

    为每个数据存储创建对 Promise 的引用 创建一个方法,如果尚未进行异步调用,则返回该方法,然后返回该承诺 将您的 async.parallel 代码替换为 Promise.all,这将创建一个新的 Promise,当所有传递的 Promise 都成功解析后,该 Promise 将被解析。 将您的 React.render 放入对承诺的 then 的调用中 - 这样只有在所有异步调用完成时才会调用它。

见下文:

var profilePromise;
var followerPromise;
var sessionPromise;    

var getProfilePromise = function()
  //If the profile promise already exists (ie, the async call has already been started)
  //then we return the promise, otherwise we make the async call.
  if(!profilePromise)
    profilePromise = new Promise(function(resolve, reject)
      MemberLoader.load(id, function()
        //Depending on the result you either call `resolve` and pass
        //in the data, or call `reject` with the error
      );
    );    
      

  return profilePromise;
;
//Repeat a version of the above function for your follower and session promise    

window.render = function (page, id, pushState) 
  var stateURL = '';    

  switch (page) 
    case 'Profile':
      stateURL = '/' + id;
      Promise.all([
        getProfilePromise(),
        getFollowerPromise(),
        getSessionPromise()
      ]).then(function(results)
        var component = React.createFactory(Profile);
        React.render(component( member: results[0], followers: results[1], session: results[2] ), mountNode);
      ).catch(function(err)
        /** handle errors here */
      );
      break;
    case 'Followers':
      stateURL = '/' + id + '/followers';
      Promise.all([
        getProfilePromise(),
        getFollowerPromise(),
        getSessionPromise()
      ]).then(function(results) 
        var component = React.createFactory(Followers);
        React.render(component( member: results[0], followers: results[1], session: results[2]  ), mountNode);
      ).catch(function(err)
        /** handle errors here */
      );
      break;
      

  if (pushState) 
    window.history.pushState( page: page, id: id , null, stateURL);
   else 
    window.history.replaceState( page: page, id: id , null, stateURL);
      

;

【讨论】:

以上是关于高效地构建具有多个视图的大型 React.js 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

如何高效地按小时查询大型数据库?

如何在mongodb中高效分页[重复]

高效地执行具有多个相似类的 CRUD 操作?

高效地在视图控制器之间切换

需要通过 PHP 将大型 CSV 文件导入多个 MySQL 表的高效方法

react.js 你应知道的9件事