Meteor React - Session best practices

Hi, I have applications based on Blaze.js and I want to transfer it to React.js.

Is it a good practice to use the “Session” package in applications based on React.js? If yes, do good practices of using this package in React.js.

I personally don’t recommend it. There are many react based solutions like react state and props, react context, mobx, redux, molecule by cultOfCoders etc.

1 Like

Thank you for the information

There are benefits to using Meteor reactive APIs like Session for state - for example, if a build is pushed (hot code push), and the page refreshes on a user half way through a form, data stored in a meteor session will persist!

You can even roll a Flux pattern with session - use a set of “actions” to set the data, and use withTracker to feed that data into your hierarchy. Flux!

3 Likes

Ah good to know, I’m wondering if it’s possible to mimic this behaviour with other state management libraries, does Meteor broadcast an event on build start/complete that we can hook to? maybe piggyback on the session to update mobx or redux…

1 Like

Session is a lot easier to implement than other equivalent tools for react. Having said that, it requires a lot of discipline. The worst thing about session is that you don’t have a centralized way of knowing which keys you have already used.

I ended up creating a devtool for our team just to keep track of the different session keys

1 Like

I’ve also wondered if there’s an easy way to use Session as a backing store for local state on a React Component. There was a lot of talk about Redux years ago, with some folks even putting ALL state in there, but that was honestly too much cognitive overhead, IMHO (and I was bullish on it years ago). It’s much easier to deal with local state in many cases - deal with the code right in front of you - and use actions and Redux or Sessions for state you really do need to flow elsewhere, and for cases where you have side effects.

One example from a recent app (context: I don’t use pub/sub, instead load data over methods, and store in offline storage in GroundDB - views are driven directly out of ground db queries) - if I have a form which submits to a method, I will need to either refresh all the data after the operation, or monkey patch the changed document in offline, after the data comes back. If I want to get fancy, I can even optimistically update the local data store, and then roll it back if the method fails. These kind of operations wouldn’t make sense deep in the bowels of a component hierarchy, but it feels pretty clean to put it in an action - and even somewhat reduxy/fluxy, without all the weirdness and rigidity.

Another almost unrelated note - I tend to wrap my withTracker in composable and reusable “connectors”. This makes it easy to find all the queries which use a particular data source (methods, pub/sub, Session, redux, apollo, whatever else), then use those to wrap my components to create containers. This also keeps all my data loading in one place, in case I want to make the jump to apollo at some point, and I almost certainly will.

I’ve actually been thinking of trying to write something up about this. It’s much easier than a lot of other approaches I’ve tried, even if I do need to clean up my mystical SSR/Serverlive/clientoffline connector a little bit. It’s a little inefficient, and a little redundant (method call to get data for fast-render on server, and fetch data on client are currently separate from the reactive/SSR query, but I think I can combine these and may the API even simpler), but it does connect all that stuff without additional effort, which is super sweet. It uses a meteor package to expose SSR to Mongo Collections directly, and on the client it exposes GroundDB, while doing all the glue on the server for SSR/fast render and hydrating/fetching the data on the client. All of this without using Meteor’s pub/sub, and it should work just as nicely for apollo. I wonder how much interest there would be in a package or at least a tutorial (or even a book - with additional stuff) for something like this.

6 Likes

I know I’d be interested. I’m taking a deep dive into SSR and dynamic imports lately, your name came up in a few results. I’ve actually been using the withTracker hoc from one of your exemple :slight_smile:

1 Like

You are right. I did mean by tools as redux, mobx, etc. I subscribe to the notion of: if component scope, use local state; hierarchy-scope, use context (if not sensitive to re-renders); the rest, Meteor sessions.

I prefer to use Meteor Session + withTracker on many things because of ease of use and reactivity that can be controlled within a component. I find redux overkill on so many things.

One thing I have not quite put in practice yet is Context + Portal. I don’t know how it will work against Meteor Session but it seems the combination can have the same effect

1 Like

Thank you for all the answers, I did not realize that the topic is so complicated and it will take some time to solve it.

It’s not, you can get away with just using react state and props and by passing the props from the parent to children, just take a look here. Session is like reactive global variable and you rarely need to use that from my experience.

Once you need global reactive variable, then you can look for more complex state management options.

2 Likes

Great article. Thanks

1 Like

That’s true, and I rarely use them too. I often just deal with the fact that local state will be wiped out if a hot-code-push happens - but even there a local ReactiveVar is probably better solution than a global session in many cases.

I am working on an app now that is getting to the point where disparate pieces need to share state. I’ve mostly gotten away with placing that in my data tier (in denormalized, or cached properties on related collections, where it makes sense), or leveraging packages that manage their own state (like accounts-base) but I have been looking at redux and sessions for some things. I’ll probably end up making some action handlers, and global sessions to store the state at some point, with my standard connector pattern to flow the data through.

1 Like

There is a new library that uses context/hooks to manage global states that got announced today on hacker news, maybe it’s worth trying as well.

I had only few cases where I needed share global state, and I used ReactiveVar for that.

1 Like

React Hooks make me feel old. I look at that code, and it just isn’t easier to read to me than a class. bah!

2 Likes

I share the same feeling as you, I personally prefer classes, but I can’t claim I’m getting younger either lol.

1 Like

I’ve been looking at hooks lately, and I’m starting to understand the appeal. React has these “use” methods - useState and useContext - I bet something similar could be done for Meteor Sessions and ReactiveVars - useSession, useReactiveVars, etc. Then we can have the benefit of persistent local state when the app pushes.

If you want to do state management on the client independent from meteor and if you are using latest react version with hooks support, i recommend to take a look at https://github.com/ctrlplusb/easy-peasy

it gives all the benefits from redux and hooks without boilerplate and bullshit. Very sexy.

Having said that, session has the one benefit from surviving hot-code-push. As @captainn suggested, this could be also a good solution in conjunction Tracker and hooks. Someone posted an implementation of such a useTracker-hook somewhere on this forum. With some small addition to that you could implement such an api:

const [value, setValue] = useSession("mysessionkey", "defaultvalue")

How about minimongo? I usually use method to load data from server and then store them in minimongo. It’s much easier to work with data in minimongo than they are in an array.
Another huge benefit of using minimongo is server rendering. In render() function, just call query to find the data you need. It will run both on client and server side (server render).

I’m moving from React components to React hooks on the front end of my Meteor app. I’m finding that in my app, it’s very easy to move from components to hooks. I prefer hooks because there’s less code overall and less confusion about how to get something to run post-render. useEffects always runs after render, whether it’s on mount, unmount, or just after a render. (There is a param that can make it run just once, or just when a specific variable changes value, etc.)

I also added React.useContext for global state. It was fairly easy to add, and easy to use. My app was getting to the point where I was passing props down through sub-components to get to where they needed to be (“props drilling”), and that’s one marker for when it’s time to add global state to a React app.

1 Like