React - best practice for passing data to components


#1

I would interested to hear how people are going about structuring the flow of data in their components.
Should I:

  1. use createContainer() to create a single wrapper for my entire app that essentially collects all the data that is required (with some if/else logic to only collect the necessary data based on what page is being called).
  2. use createContainer() wrapper for every single one of my components and collect the data that is only relevant to that component (this will mean that some data will be collected more that once).
  3. Other (if so, what would this be?)

?


#2

I think the idea is to use containers for each component and then place those containers in a parent container for components that share the same data.

So you get a structure like this:

<ParentContainer data={shared}>
  <ChildContainer1 data={specific} props={shared}>
    <Component1 props={specific, shared}/>
  </ChildContainer1>

  <ChildContainer2 data={specific} props={shared}>
    <Component2 props={specific, shared} />
  </ChildContainer2>
</ParentContainer>

This way you don’t need if/else logic and each container is still concerned about it’s own piece of data


#3

ok, probably best to give an example of the issues I’m having, which revolves around haivng to dynamically load components in based on certain criteria.

The simplified structure of my app is as follows:

<AppWrapperData>
    <AppWrapper>
        <Menu />
        <PageLayout1>
            <ContentBlockDataA>                
                <ContentBlock />
            </ContentBlockDataA>
        </PageLayout1>
        <PageLayout2>
            <ContentBlockDataB>                
                <ContentBlock />
            </ContentBlockDataB>
        </PageLayout2>
    </AppWrapper>
</AppWrapperData>

What I need to do allow the app to decide which page layout it needs to show and then insert a number of different components into the page layout. The app won’t know what component to insert without some additional criteria (perhaps sent down from FlowRouter).

The way that I am doing it is:

  1. FlowRouter renders the first container which gets genenric application data.

    app.route(’/someurl’, {
    action: function(params, queryParams) {
    ReactLayout.render(AppWrapperData, {
    params: {
    appPageLayout: <PageLayout1 {…this.props} contentContainer={<ContentBlockDataA {…this.props} />} />
    }
    });
    }
    });

  2. AppWrapperData: the initial data container is as follows:

    export default createContainer(({ params }) => {

     const dataHandle = Meteor.subscribe('UsersExtraPub');
     const dataUsersExtraIsReady = dataHandle.ready();
     return {
         dataUsersExtraIsReady,
         dataUsersExtra: dataUsersExtraIsReady ? UsersExtraColl.find().fetch() : []
     };
    

    }, AppWrapper);

  3. AppWrapper: The generic app component is as follows:

    export default class AppWrapper extends React.Component {

     constructor(props) {
         super(props);
     }
    
     render(){
             return (
                 <div>
                     <Menu {...this.props} />
                     <div className="page-content">
    
                         {this.props.params.appPageLayout}
    
                     </div>
                 </div>
             )
     }
    

    };

  4. PageLayout1: The page layout component is as follows:

    export default class PageLayout1 extends React.Component {

     constructor(props) {
         super(props);
     }
    
     render(){
    
         return (
             <div>
                 <div className="module-header">
                     <div className="container-fluid">
                         <div className="row">
                             <ul className="nav nav-tabs">
    
                                 <li role="presentation" className="active"><a href="#">Information</a></li>
                                 <li role="presentation"><a href="#">Designer</a></li>
    
                             </ul>
                         </div>
                     </div>
                 </div>
                 <div className="module-content">
                     <div className="container-fluid">
                         <div className="row">
                             <div className="col-md-12 col-lg-11">
    
                                 {this.props.contentContainer}
    
                             </div>
                         </div>
                     </div>
                 </div>
             </div>
         )
     }
    

    };

Now, there are two problems with this. First problem is that I am passing components down from FlowRouter by specifying {this.props.params.appPageLayout} this does not allow me to pass props into the PageLayout1 component. So, should I be doing an if/else like this instead?:

{(() => {
  switch (this.props.params.appPageLayout) {
    case 1: return <PageLayout1 {...this.props} />;
    case 2: return <PageLayout2 {...this.props} />;
    default: return "";
  }
})()}

The second problem is that once I am in the PageLayout1 component, a decision needs to be made automatically about which components are to go inside it. If I do another switch statement, then I will have to repliacte this inside the PageLayout component.

Something doesn’t feel right about the way I’m tackling this, so any help would be appreciated :slight_smile: