【问题标题】:Efficiently structuring large React.js applications with multiple views高效地构建具有多个视图的大型 React.js 应用程序
【发布时间】: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); 
  }
});

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

【问题讨论】:

    标签: javascript reactjs reactjs-flux


    【解决方案1】:

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

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

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

    1. 为每个数据存储创建对 Promise 的引用
    2. 创建一个方法,如果尚未进行异步调用,则返回该方法,然后返回该承诺
    3. 将您的 async.parallel 代码替换为 Promise.all,这将创建一个新的 Promise,当所有传递的 Promise 都成功解析后,该 Promise 将被解析。
    4. 将您的 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);
      }    
    
    };
    

    【讨论】:

      猜你喜欢
      • 2010-09-06
      • 2013-11-20
      • 2012-08-03
      • 1970-01-01
      • 2013-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多