javascript - 高效构建具有多个 View 的大型 React.js 应用程序

标签 javascript reactjs reactjs-flux

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

例如,假设 Profile 已加载并且用户单击“查看关注者”。那时,调度员收到一条消息,内容为 gotoFollowers。然后在顶层渲染一个全新的 React 组件(即 Followers 组件)。不幸的是,FollowerProfile 组件都需要类似的数据(例如 session 数据、用户照片、用户名,甚至还有关注者,因为我们在 上显示了关注者的片段>简介)。因此,每次用户更改页面时都必须在顶层重新呈现(包括执行 ajax 调用)感觉非常浪费。

我假设我做的不正确。我应该使用单父 React 组件吗? (我也看到了问题)我应该如何构建具有多个 View 的大型 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); 
  }
});

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

最佳答案

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

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

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

  1. 为您的每个数据存储创建对 promise 的引用
  2. 创建一个方法,如果尚未进行异步调用,则返回该调用,然后返回该 promise
  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);
  }    

};

关于javascript - 高效构建具有多个 View 的大型 React.js 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29649272/

相关文章:

reactjs - 无法更改 react-elastic-carousel 中的点样式

javascript - ReactJS - 等待 Action 在 componentDidMount 中完成

javascript - 发出多个 ajax 请求时,是否有 "good pattern"用于跟踪响应与哪些数据对齐?

javascript - react-native android 中此问题 "Cannot convert argument of type class org.json.JSONArray"的原因是什么?

javascript - 如何获取 html.erb 文件中的 JavaScript 以在 Rails 4 应用程序中呈现?

javascript - 构建拖放导航选项卡

javascript - 使用 angularjs 使用递归函数从 json 数据生成节点树

javascript - github 中的 Codacy 功能给了我一些我无法理解的错误

javascript - 如何下载获取响应作为文件 react

javascript - 向 Javascript 计时器添加前导零