arunoda / react-komposer

Feed data into React components by composing containers.
MIT License
732 stars 70 forks source link

Two components with same subscription #136

Closed paulo2nd closed 7 years ago

paulo2nd commented 7 years ago

Here is my problem, I have two components that needs same subscription, the problem is:

After access the second component the first one loose the reactivity.

arunoda commented 7 years ago

For that, you could use something like subs-manager. I don't think this is something we should address with React Komposer level. Anyway, I'd like to see some code.

paulo2nd commented 7 years ago

Here are the 2 containers:

import { Meteor } from 'meteor/meteor';
import { Tracker } from 'meteor/tracker';
import { compose } from 'react-komposer';
import UserSolution from '../../collections/UserSolution';
import MySpace from '../pages/MySpace';

function getTrackerLoader(mapper) {
  return (props, onData, env) => {
    let trackerCleanup = null;
    const handler = Tracker.nonreactive(() => (
      Tracker.autorun(() => {
        trackerCleanup = mapper(props, onData, env);
      })));

    return () => {
      if (typeof trackerCleanup === 'function') trackerCleanup();
      return handler.stop();
    };
  };
}

function reactiveMapper(props, onData) {
  if (Meteor.subscribe('userSolutions').ready()) {
    const solutions = UserSolution.find().fetch();
    onData(null, { solutions });
  }
}

export default compose(getTrackerLoader(reactiveMapper))(MySpace);
import { Meteor } from 'meteor/meteor';
import { Tracker } from 'meteor/tracker';
import { compose } from 'react-komposer';
import Message from '../../collections/Message';
import Chat from '../../collections/Chat';
import ChatDetail from '../pages/ChatDetail';
import { _ } from 'meteor/underscore';

function getTrackerLoader(mapper) {
  return (props, onData, env) => {
    let trackerCleanup = null;
    const handler = Tracker.nonreactive(() => (
      Tracker.autorun(() => {
        trackerCleanup = mapper(props, onData, env);
      })));

    return () => {
      if (typeof trackerCleanup === 'function') trackerCleanup();
      return handler.stop();
    };
  };
}

function reactiveMapper(props, onData) {
  const { chatId } = props.params;
  if (Meteor.subscribe('userSolutions').ready() &&
  Meteor.subscribe('messages', chatId).ready()) {
    const chat = Chat.findOne({ _id: chatId });
    let messages = Message.find({ chatId }).fetch();
    messages = _.sortBy(messages, 'createdAt');
    onData(null, { messages, chat });
  }
}

export default compose(getTrackerLoader(reactiveMapper))(ChatDetail);

need this because chat information come from userSolutions publication.

arunoda commented 7 years ago

I assume you need some help with Meteor. Specially with subscription caching. I think this question better suits for stackoverflow or in the Meteor forums.

Anyway, you don't need to create getTrackerLoader on each and every file. Just create it once and use it.

paulo2nd commented 7 years ago

This was not the real code, write it because changed the original.

I agree, I need to understand more about subscription cache, but as I see this would be only a performance issue. The think is subscription should be destroyed and recreated in every new route.

I think I know my problem, I am using react-router instead flowrouter and react-router are not recreating the component when user come back to previous route. In this case even subs-cache will not help me.

Thank you for the help.