React Dynamic Query


#1

Good day meteorites!

I’m just starting to learn Meteor using React as the view layer and I stumble upon a problem of updating the query that is provided in createContainer() method.

In the tutorial of React it’s recommended that you do the query in the createContainer() method stated in collections section of the tutorial like below:

export default createContainer(() => {
  return {
    tasks: Tasks.find({}).fetch(),
  };
}, App);

What is the idiomatic way for Meteor to update the Tasks.find({}).fetch() to have query like sorting:

Tasks.find({}, { sort: { createdAt: 1 } }).fetch()

Thanks for help!


#2

Check out this forum thread, and in particular this response:

You could leverage one of the many available state management methods (ReactiveVar, ReactiveDict/Session, Redux, etc.) to access a sort field/order that was selected in some other component, and use it in your createContainer function.


#3

Do you have sample code snippet to demonstrate this? I tried using the ReactiveVar but when I use it’s #set() mtehod it doesn’t trigger re-rendering of the container:

export default createContainer(() => {
  const reactiveQuery = new ReactiveVar({ sort: { createdAt: -1 } });
  
  const _sort = function (ev) {
    reactiveQuery.set({ sort: { createdAt: 1 } });
  };

  return {
    tasks: Tasks.find({}, reactiveQuery.get()).fetch(),
    sort: _sort
  };
}, App);

#4

Sure - I’ve thrown together a quick example below. The issue with your code snippet is that you’re initializing your ReactiveVar within the createContainer() function. Each time createContainer is called, you’re clobbering your new ReactiveVar value. Here’s a quick example showing how you can work around this:

1) WidgetContainer.js

import { createContainer } from 'meteor/react-meteor-data';

import widgets from '/imports/api/widgets/collection.js';
import WidgetList from '../components/WidgetList.js';

const sort = new ReactiveVar(1);

const WidgetContainer = createContainer(() => {
  const allWidgets = widgets.find({}, { sort: { name: sort.get() } }).fetch();
  return {
    allWidgets,
    sort
  };
}, WidgetList);

export default WidgetContainer;

2) WidgetList.js

import React from 'react';

class WidgetList extends React.Component {
  constructor(props) {
    super(props);
    this.changeSortOrder = this.changeSortOrder.bind(this);
  }

  changeSortOrder(event) {
    event.preventDefault();
    this.props.sort.set(
      this.props.sort.get() === 1 ? -1 : 1
    );
  }

  render() {
    let widgetContent = [];
    this.props.allWidgets.forEach((widget) => {
      widgetContent.push(
        <li key={widget._id}>{widget.name}</li>
      );
    });
    return (
      <div className="widgets">
        <a href="#" onClick={this.changeSortOrder}>Change sort order</a>
        <ul>
          {widgetContent}
        </ul>
      </div>
    );
  }
}

WidgetList.propTypes = {
  allWidgets: React.PropTypes.array,
  sort: React.PropTypes.object,
};

export default WidgetList;

#5

Thanks @hwillson! It is working great now. I missed that the callback function you passed to createContainer() method will be re-executed if there is a change in your data subscriptions, which in our case the ReactiveVar.