Effectively structure large React.js applications with multiple views

I have a responsive application with several views (e.g. Profile,, Followers). Each of these views currently lives as its own React component, which runs both on the server side and on the client side. I'm starting to struggle to understand the right way to structure my code.

For example, let's say it Profileloads, and the user clicks "See Followers". At this point, a message is sent to the dispatcher gotoFollowers. At the top level, we then create a whole new React component (i.e., Component Followers). Unfortunately, the components Followerand Profilerequire similar data (for example, session data, userphoto, username and even followers, because we show a fragment of subscribers to Profile). Thus, it is very rarely necessary to redraw at the top level (including making ajax calls) every time the user changes the page.

I assume that I am not doing it right. Should I use the parent reagent component? (I see problems with this too) How can I structure large React applications with many views?

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

Note . Our application is displayed both on the server and on the client side.

+4
source share
1 answer

To solve the problem of getting the same data several times, you should study Promises - it can replace the asynclib you are using right now.

Promises , . - , .

() - .

  • promises
  • , , ,
  • async.parallel Promise.all, , , promises .
  • 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);
  }    

};
0

All Articles