Meteor 1.3 + react + reactRouter best practices


#1

Hi All,

DISCLAIMER: this is going to be a long question, I apologize.
I am new to meteor, so I also apologize if the questions are a bit naive.
I have some troubles figuring out the best way to handle data in conjunction with react and react router.
Last disclaimer: I manage to achieve the kind of result that I need but this is not a question about how to simply achieve the result, is a question trying to understand what are the best practices that I should follow.

So far I understood that one pattern is to have the router point to root components that use createContainer to fetch some data and pass it to children components. I have seen this pattern in the react todoList on github (https://github.com/meteor/todos/tree/react) and mentioned in the guide and on the forums as well.

However I have several things that are not really clear in my mind especially regarding the connection between routes, RootContainers (the components that implement createContainer) and presentational components. They are all related to each other, so more than an answer question by question I would also appreciate if somebody can give me a generic high level overview of how an application components hierarchy and routes should be setup to have the best results in terms of code reuse, performance, maintanability, etc.

CreateContainer asks to specify as a parameter the react component to which the data will be passed to in the props. How do I share the same container between multiple children? The only way I can think of is to have createContainer point to a middle-layer ParentComponent that will then clone and render its children (similar to what the AppContainer does in the react todo github) . But to me it looks like a lot of boilerPlate code, is there anything more simple if I simple want two presentational components to both access the same collection? Do I really have to always create an intermediate component to pass to createContainer that just clones and renders the children?

Let’s assume I want to achieve this kind of components hierarchy and 2 collections, Categories and Products, where there are multiple products in one category. (linked by categoryId)

<MainUI>
  <CategoriesPage/>
  <AllProductsPage/>
  <ProductsInCategoryPage/>
  <ProductDetailPage/>
</MainUI>

where the whole app needs to have access to the loggedIn user, CategoriesPage needs to have access to the entire categories collection, AllProductsPage need to have access to all products collection, ProductsInCategoryPage need to have access to the Products in one category, and ProductDetailPage needs to have access to a specific product.

How Would I setup this in terms of react components and routes?

The mainUI could be a rootContainer that uses createContainer to register to the meteor user data, passes it to a rootLayout that renders the title, the theme, and clones&render the children.
But what about the other pages?

Should we register to products&categories collection also in the mainUI and then pass it down to the children? This would require potentially passing it through children that don’t really care about that data, and moreover would always listen to all the collections in any page in the app, so I don’t like it.

Should we have a “CategoriesContainer” and a “ProductsContainer” as children of MainUI, and these two have the other pages as children? That would work for CategoriesPage, AllProductsPage and ProductDetailPage, but what for ProductsInCategoryPage that needs both?

Should each one of the pages be a rootComponent with its own createContainer call, even if they share most of the data? Aside for being super verbose (creating a lot of container components for the same collections), how would this behave with meteor? I mean, in that case there would be a container fetching all categories, one fetching all products, one fetching all products with a certain categoryID, and the last container fetching a product with a certain productId. How would this work if a user visits all the pages? Would the data be fetched multiple times? Or would it be fetched only once and then just queried locally from minimongo? Would the 4 createContainers reactive functions be less performing than having a single one, even if they listen to the same collections?

Or should we set it up even differently?

Another question:
What if I know that some of those collections will be pretty static and I don’t want to reactively listen on them but just fetch them once? Should I still put the find() inside a createContainer just to listen to its initial loading from the server? Should I stop listening by manually calling stop() after the initial loading to release resources?

Another question:
if a parentContainer (for example the root mainUI container) fetches a collection inside a createContainer() call and wait for it to be loaded before rendering the children, can the children access its data just by importing the collection in the file and call find().fetch() ? Example, the parent container fetches all products, and one of the child wants to fetch a speficic product by productId… If he imports the products collection and call products.findOne({productId}) will the product already be available or he needs to receive it from the parent as props?

I apologize again for the length and messiness of the question, I have the feeling I am grasping the generic concept but I am getting confused in the practical details. Good karma and kudos to whoever can makes sense of my confusion and give me a enlightening explanation.

Cheers,


Meteor 1.3 + react
#2

hey bud,

have a look at https://themeteorchef.com/base/

I did not have much of an idea about how to go about this stuff either in react. The only downside (and this is because i am a noob) is that the containers meteorchef uses enforce pure react components. That is, any state would have to be done in redux or something. But basic authentication, routing etc is super easy with this…

So there is a layout component, which is the gateway to everything else. Some basic fixtures are also present. WIthin the layout component, are pages. The way the original was done is that the pages call containers, starting with a app navigation container. App nav breaks into authenticated and public pages. Add pages as required is the idea, each with dedicated containers where the subscription is handled.

For my app, basically I only add pages. Here i did it differently from the original. I changed the pages to be stateful, and turned it into a high level nav basically. Components within the nav is the level at which i do subscriptions (createcontainer etc).

Thanks so much.

Tat


#3

Hi tat,

thank you so much for the answer.

Does that mean that if you have 50 pages you have 50 containers and 50 ‘presentational’ components? Even if those 50 pages actually work only on the same 3-4 collections?

It’s the same organization that I am having in my app, but somehow it looks dirty to me, really not DRY. You end up creating a lot of boilerplate containers over and over again, with almost the same code.

I had a look at the masterchef base project and indeed using react-komposer helps a bit because at least it automates the loading/errorhandling code, so I might starting use that one over the createContainer one.

Still it looks like you need to have 1 container for 1 page component, even if they should be possibly shared for pages that work on the same data.

I would simply like a container library that does what react-komposer does, with the ability to specify as parameters which collection to fetch, which selectors (if any), and which react component to use as children, but it seems that noone has all the features together and you always have to implement it yourself.

I find really frustrating that all the examples/guides/tutorials you find around containers are always around the most trivial/easy setup and never really fit a real scenario, for example pages handling multiple controls with user inputs, states, etc.


#4

Hi @mastrolindo,

Nah - the way i have done it is to have say 5 pages, which each relate to some combination of the 5 collections I’m working with. In addition there are say another 5 pages which act as helper to certain actions, login, verify token for password reset whatever. So the first 5 are where the action is in terms of business logic.

The pages themselves are staging grounds for a large number of components. Lets say page 1 is a admin function. Here i work with user stuff and say, entity stuff. This is where I do the subscription, using the createContainer pattern, as opposed to the react composer pattern, for say meteor.users, the roles-list, and the entitiy-list, or whatever.

All components beneath this page, simply get props. So I only have 5 places where i am handling subscriptions, 1 for each page. Lots of components underneath each page with props as needed.

For what it is worth, I’m not convinced this is the best way to do it. As far as I can tell, I’m leaving stateful stuff everywhere. As I am still developing the app, this works for me. Once it is done, I will re-factor. I spent too much time thinking about structure, and I’m not sure it got me anywhere.

The other factor is that I think I want to have state and subscriptions in the lowest components. Why? Well, if I get traction, then I can optimize. Otherwise, it is far easier to add server capacity than squander scarce resources on the client side. It is better to have load on my server, in all but the most extreme scenario’s, than have a lean system on my end with the client doing the majority of the work.

Dude I am still learning… Will see how I go.

Tat

P.S. I went with react-composer first too, but it is simply too restrictive in terms of not allowing state at all. I’m pretty sure this is just my lack of familarity with react/JS, but it is what it is… The fact that react composer throws the turning thing while it loads was simply not worth it.