Moving data between react components

Hey guys,

I’m trying to make some data that is generated in one of my components available to other components and I can’t seem to get it working.

I’ve tried using Session and State but neither work.

I can’t pass props (I don’t think) due to my layout. Basically it’s like this…

Sidebar | Content
Footer

I have a MainLayout component that imports lots of other components being used in the project.
I’m using react-router-dom for my routes and all of my routing is being done inside this component. It serves up the same sidebar and footer components for every route but the Content is loaded with other components depending on the route.

The Sidebar contains NavLinks that update the components in the Content area.
The Content area has components rendered inside that generate data which I need to somehow get into my Footer component.

As the Footer component is not a child component of what is rendered in Content (so therefore I can’t pass down props to it) I’ve come a bit unstuck.

I thought using Session would do it but I’m getting undefined errors. I also tried using persistent-session to do this but got a whole ton of errors (probably due to the fact I’m using the latest Meteor codebase?). I read some posts that said React ignores Session completely so that explains why it isn’t working and I know state is only valid in the component it is declared in.

So if I can’t use state or session to pull stuff out of my Content components how else can I achieve it?

Some options:
Redux - common for state management in React app, but increases complexity quiet a lot
reactive-var/dict - use together with withTracker and you can have that as a reactive state outside of components.

1 Like

You could pass a function as a prop to content that updates the footer. Then in the content block you can simply call the function with params.

Alternatively, use https://reactjs.org/docs/context.html

2 Likes

Ahh that’s fantastic thank you!

And there’s no issue declaring the .dicts inside a react component?

I wish it were that simple.

There is an onClick event inside one of the Content components that generates the data I need to send to Footer. I can see that quickly getting very messy.

Okay tried that…

Installed the package.

Put …

var dict = new ReactiveDict('myDict');
    dict.set("weather", "cloudy");

… inside my onClick function

Then tried console logging like this in the same component :

export default withTracker(props => {
  console.log(dict.get("weather"));
})(ListDetail);

And I’m getting :

Exception from Tracker recompute function: 
ReferenceError: dict is not defined

Do I have to import react-dict? It didn’t say anything in the docs.

Forget that, I’m an idiot…

Of course it was undefined as I was trying to console.log it before it had been set in the onClick function…

Time for bed I think :joy:

Okay had one more shot before bed…

I can only seem to be able to declare the dict in my onClick function and then it can only be declared once before throwing errors (so not much use in an onClick function).

Same goes if If I try to put it anywhere else, like in the constructor, it crashes the app saying :

Error: Duplicate ReactiveDict name: myDict

Where am I supposed to declare the var?

I found this in the docs but it doesn’t help me as it seems to be using Blaze templates.

This is why https://github.com/cult-of-coders/react-molecule was invented. Check it out!

3 Likes

This looks like exactly what I’m after! Thank you!

You know what, after trying everything mentioned above, the simplest approach seems to just use good old vanilla JS or jQuery to pass the data vars around. No idea why I didn’t think of this in the first place?

When I moved to React, I also dropped JQuery.

I’m not sure why the suggestions above were not working. Here are the things that worked for me:

  1. React Context API - this is new to React 16.x
  2. Meteor Session + withTracker

Was just looking at Context, seemed like it could be a solution but I’m having to use React 15.3.1 on this project as one of the modules I’m using doesn’t support anything higher.

Ideally, you are not mixing React with anything that can change the DOM directly (e.g. jquery). The single-source of truth must be the virtual DOM and the state variables.

That’s exactly what I was hoping for, which is probably also why my brain didn’t even entertain the idea of using jQuery for this before, but I just can’t get Sessions working. The React components just ignore them completely. Always return “undefined”. Is there a good primer for using Sessions with React anywhere? I’ve read the Meteor docs but It’s just not working for me.

I’m typing this directly so this might have errors:

import { Session } from 'meteor/session';
import { withTracker } from 'meteor/react-meteor-data';
import React from 'react';

class Sample extends React.Component {
  constructor(props) {
    super(props);
  }

  componentDidUpdate(prevProps) {
    if (prevProps.reactiveData !== this.props.reactiveData) {
      console.log(this.props.reactiveData);
    }
  }

  render() { return null; }
}

export default (SampleContainer = withTracker(() => {
  let reactiveData = Session.get('sampleData');

  return { reactiveData };
})(Sample));

Now, you can call Session.set('sampleData', 'sample value'); anywhere and the component will be updated with this.props.reactiveData equals to 'sample value'

1 Like

Thank you so much! This is the part I was missing. Working as expected now :slight_smile:

I have been working on a big application with Meteor + React, majority of issues I encountered was handing inner state communications between components and handing initial empty props when subscription is not ready.

I have tried number of solutions including Redux, but my code was over complicated and made it difficult for other developers and myself to maintain it.

I have started using a state management library called undux , simplified version of Redux with an API similar to Meteor Session and it tremendously improved my workflow!

3 Likes

try mobx too - its fantastic!

1 Like