Search code examples
callbackreactjsparent-childreactjs-fluxflux

Parent Component react to multiple children component inputs


I am a bit confused how to build my react/flux (flummox) app in a nice and understandable way.

I have a Parent component called StrategyListwhich displays a filterable list of "strategies". The strategies are stored in a StrategyStore (Flux). Now my StrategyListalso has a reusable child component ListFilter, which renders a dropdown to chose a category and a searchbox to filter the list.

Because my ListFilteris reusable, I pass two callbacks to it:

<ListFilter
  onSearchQueryChange={this._handleSearchQueryChanged.bind(this)}
  onCategoryChange={this._handleCategoryFilterChanged.bind(this)}
  ...
/>

Now if any of the filter values has changed (either the category or the search query, I want to call a flux action on my parent StrategyListcomponent to get new List Items from the API.

In about every example out there, they have a child component with a callback and then the parent does something like this:

_handleSearchQueryChanged(searchQuery) {
  this.props.flux.getActions('strategyActions').fetchData(searchQuery);
}

Seems nice and it works like that. But... If i fetch data, I need to send both the category and the search query! I can not rely on the callback parameter only. I can only get the data trough the two specific onChange callbacks, I need to store the values somewhere in my parent component, right?

I am now confused if I should:

1. Store category & searchQuery in my StrategyListcomponent's state?

_handleSearchQueryChanged(searchQuery) {
  this.setState({
    searchQuery: searchQuery
  };

  this.props.flux.getActions('strategyActions').fetchData(
    this.state.category, 
    this.state.searchQuery);
}

// Same for category...
  • When I've done that, it seems that the action never gets the actual state data, but is always one step behind (because setState is not synchronous?)

2. Store category & searchQuery in my store?

For that, I would call a Flux action in the callback to save the data from the input fields.

_handleSearchQueryChanged(searchQuery) {
  this.props.flux.getActions('strategyActions').setSearchQuery(searchQuery);
}
_handleCategoryFilterChanged(category) {
  this.props.flux.getActions('strategyActions').setCategory(category);
}

But in this case, where do I actually call the fetch action? At what time do I know that either one of the two values has changed and I need to fire the data loading? Also it seems like an unneccessary overhead to creat actions only to save the values to an application-wide store where they are never used.

3. Somewhere else? Context? ReactLink? How do I access the values?

I cannot access the child elements via this.refs.* because at least the Drop-Down is a higher-level componenent (material-ui) with no ref, but only a callback (its composed of divs, not a select-field).

Thank you for helping.

Robert


Solution

  • As I've been working with the Flux pattern, I found it more useful to use actions to mutate data in the stores and to not use actions when the stores don't need to change anything to react to my request.

    If I do want to update the stores, I send an action that contains my updaye. Stores listen for relevant actions and update themselves. Then, when data changes, my stores emit change events that I can listen for in the components connected to those stores. But when it's just time to get data from the store (either in response to one of these events telling me the store's data has changed, or any other time I need fresh data), I just use MyStore.getTheData(category, filterText).

    For your case, I'd recommend storing category and filterText in the StrategyList state and implementing a data getter function in the StrategyStore to return the data to you, filtered as you would like to see it.