Javascript 使用多个视图高效构建大型React.js应用程序

Javascript 使用多个视图高效构建大型React.js应用程序,javascript,reactjs,reactjs-flux,Javascript,Reactjs,Reactjs Flux,我有一个react应用程序,具有多个视图(例如,Profile,Followers)。这些视图中的每一个当前都作为自己的React组件存在,该组件在服务器端和客户端都执行。我开始努力理解构造代码的正确方法 例如,假设加载了Profile,用户单击“查看关注者”。此时,调度器会收到一条消息,上面写着gotoFollowers。在顶层,我们然后呈现一个全新的React组件(即Followers组件)。不幸的是,Follower和Profile组件都需要类似的数据(例如会话数据、用户照片、用户名,甚至

我有一个react应用程序,具有多个视图(例如,
Profile
Followers
)。这些视图中的每一个当前都作为自己的React组件存在,该组件在服务器端和客户端都执行。我开始努力理解构造代码的正确方法

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

我想我做得不对。我应该使用单亲组件吗?(我也看到了这方面的问题)我应该如何构造具有多个视图的大型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); 
  }
});

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

要解决多次获取相同数据的问题,您应该研究-这可能会取代您现在使用的
async
lib

承诺允许您进行一次异步调用,但即使在调用成功后也会附加回调。您可以保留对承诺的引用,并在以后的应用程序中使用它,而无需检查承诺是否已得到解决

我在下面为您准备了一个(未经测试的)示例实现——它可以做一些事情

  • 为每个数据存储创建对承诺的引用
  • 创建一个方法,该方法返回异步调用(如果尚未进行),然后返回该承诺
  • 将您的
    async.parallel
    代码替换为
    Promise.all
    ,这将创建一个新的Promise,该Promise在成功解析所有传递的Promise后被解析
  • 将您的
    React.render
    放在对
    的调用中,然后在promise上执行
    ——这样,只有在所有异步调用完成后才会调用它
  • 见下文:

    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);
      }    
    
    };