0

I am learning a react/redux and have an application with two main pieces of state:

  1. An array of items
  2. An object that contains user-specified filters for those items

I have three functions/actions, createFilter, updateFilter, and deleteFilter that modify the state of #2. I have an action filterItems that modifies #1 based on the state of #2. So whenever #2 changes, this action needs to be dispatched.

This is the component I am working with:

import React, { Component } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'

import { createFilter } from '../actions/actions'
import { updateFilter } from '../actions/actions'
import { deleteFilter } from '../actions/actions'
import { filterItems } from '../actions/actions'

class ItemList extends Component {

 createFilter(input) {
       this.props.createFilter(input)
       this.props.filterItems()
    }

    updateFilter(input) {
       this.props.updateFilter(input)
       this.props.filterItems()
    }

    deleteFilter() {
       this.props.deleteFilter()
       this.props.filterItems()
    }

    ...
    // Render method
    ...
}

function mapDispatchToProps(dispatch) {
    return bindActionCreators({ createFilter, updateFilter, deleteFilter, filterItems }, dispatch)
}

function mapStateToProps({ itemList }) {
    return { itemList }
}

export default connect(mapStateToProps, mapDispatchToProps)(ItemList)

What I have found is that when one of the filter methods are sent, the store (state #2) is not yet updated by the time filterItems() is called.

So I need to asynchronously execute the filter functions, and once the store is updated call filterItems.

I am struggling on how to do this with react-thunk. If the first function was an ajax promise I would use .then():

export function updateFilterAndEvaluate(input) {
    return (dispatch, getState) => {
        updateFilter(input).then(dispatch(filterItems(getState().filters)))
    }
}

But these are just functions, and don't have a .then() method. I am trying to figure out what my best course of action is for this implementation. Can I wrap Redux actions in a promise? Am I misusing Thunk? Or should I attempt a different pattern entirely?

1
  • 1
    Why wouldn't updateFilter return a Promise ? Commented Apr 15, 2016 at 8:21

1 Answer 1

6

I have an action filterItems that modifies #1 based on the state of #2.

This is, generally speaking, an anti-pattern. Since the result array can be computed from the source array and the currently active filters, you shouldn’t be keeping it in the state.

Redux actions should generally look like “events” (e.g. what happened). “Filter was created” and “filter was updated” are good actions. “Filter them now!” looks more like a command, this is usually a sign that it shouldn’t have been an action in the first place, and should be something the components do as they select the data to render.

Instead, do the filtering as part of your mapStateToProps() function when you prepare data for the components. If it gets expensive, look into using Reselect to compute derived data efficiently.

As for your specific question,

What I have found is that when one of the filter methods are sent, the store (state #2) is not yet updated by the time filterItems() is called.

This is incorrect and indicates some other problem in your code. (It’s hard to tell where because the example is incomplete). In Redux, dispatch() is synchronous (unless you have some middleware that delays or batches it which usually isn’t the case), so you don’t need to “wait” for it to finish if it just operates on the local data.

However, in any case, filterItems() is not a very good fit for an action, and I suggest you to look into filtering in mapStateToProps() as I wrote above.

Sign up to request clarification or add additional context in comments.

4 Comments

Awesome, thanks! This makes sense. I have a working version of it by filtering in the mapStateToProps method of the component. As a follow up question, what if as the items pass through the filters they are modified by the filters? Then they would need to be dispatched in an action to update the store with their new modified state correct?
Why would filters modify the items? I don’t understand the use case. If they just “format” some things that change temporarily while the filter is applied, I would expect that mapStateToProps copies whatever it needs to modify, and passes down that as props. mapStateToProps can never dispatch actions, it should be a pure function.
I am just experimenting, but the use case would be to store an identifier for the filter in the item so that, if that item were to be filtered again, it can bypass filter logic and be approved. I can also move the filtering inside the component too.
Why would it need to bypass the logic? If you’re concerned about performance, please see the third paragraph in my answer: “If it gets expensive, look into using Reselect to compute derived data efficiently.” Redux documentation has a page dedicated to this exclusively.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.