React-Komposer + Flow-Router (Reactive Action): How to change filter on collection via props?


#1

Hi out there,

I am a bit struggling with a “Blaze” simple question but get lost when trying to solve this using React, Flow-Router, React-Komposer.

I have 3 Elements:

  1. MainLayout
  2. SearchEntry (InputBox)
  3. ItemsList

The app will subscribe to the complete collection “items” on start to sync all data to the client. Then I just want to filter the items list whenever something is entered in the SearchEntry

To save the current searchBy state I may either use a ReactiveVar or a Component State.

stateVar_searchBy = new ReactiveVar("");

My FlowRoute looks like:

FlowRouter.route("/", {
  action(params) {
    mount(Layout, {
      header: <searchEntry />,
      content: <ItemsList searchBy={stateVar_searchBy.get()} />
    });
  }
});

I mount data using react-komposer

function composer(props, onData) {
  const handle = Meteor.subscribe("items");
  if (handle.ready()) {
    const items = Items.find(props.searchBy == "" ? {} : { title: new RegExp(props.searchBy, 'i') }).fetch();
    onData(null, {items});
  };
};

export default composeWithTracker(composer)(ItemsList);

My Problem is now, that the composer function is not reactive, so whenever I change the value of my ReactiveVar stateVar_searchBy the List won’t get re-rendered.

Q: My question is now how I may change the props value of the ItemsList to get a new filtered list based on the search input.

Thanks for some help on this
Tom


#2

I do something like the following for bowling center application…
I use a global ‘theApp’ for storing the filter (and everything else the app uses).
Here is my container … the filter is reactive and is being updated by the component

import theApp from '/imports/startup/client/theApp.js'
import { composeWithTracker } from 'react-komposer';
import { Bowlers } from '/imports/api/collections';
import { SelectBowlerAll } from '../components/select-bowler-all.js';
import { Loading } from '../components/loading.js';

const composer = (props, onReady) => {
  const filter = theApp.selectAllFilter.get();
  const handleData = theApp.theSubsManager.subscribe('leagueBowlersAll', filter);

  if (handleData.ready()) {
    const data = Bowlers.find({ name: new RegExp(filter,'i')}).fetch();
    onReady(null, { data, filter });
  }
};
export default composeWithTracker(composer, Loading)(SelectBowlerAll);

the component looks like this … where the filter gets updated

const handleChange = (filter, event) => {
    theApp.selectAllFilter.set(event.target.value);
}
export const SelectBowlerAll = ({ data, filter }) => {
  ...
    return (
       <div className="text-center">
      <h3>Select a Bowler</h3>
      <input  autoFocus type="text" placeholder ='Bowler name...' value={filter}  onChange={handleChange.bind(this, filter) } />
     </div>
    );

#3

Hi Paul ( @stocksp )

thanks for posting. So you don’t use a components prop but some global reactive data for your filter.

I really would like to know how to do this via a component prop so that the component may function without some global knowledge.

Maybe someone could guide us about “the react way”?


#4

All the react examples I’ve seen use a global store (like Redux) for holding on to the ‘filter’ … my ‘store’ is ‘theApp’.


#5

I am not sure if even that all seen so far are doing via globals is the correct and really preferred solution for that.

@arunoda maybe you may chip in and give us some short guidiance (maybe also how to do it mantra style)

Thanks all for comments
Tom


#6

I updated the title for better understanding and in hope to get some more response.

Thanks for help in advance.
Tom