Codementor Events

Curry away in React

Published Dec 30, 2017
Curry away in React

So you’re going to build the next-gen eCommerce company selling dog supplies and you’ve decided to use React to build it with coz, you know, its all the rage now and choosing a front-end framework is the “first and most important responsible step” towards building any successful online business.

I’d like to share a neat trick I learned while building my own eCommerce website, obviously next-gen coz React!

Filtering products based on various aspects is a staple in any shopping site and so let’s add some filters to the product results page.


This is where our customers filter and find the right products for their dogs 😃

As any ‘good’ React developer would, let’s break up this UI into components which is pretty straight forward in our case.


This is what React developers see when they visit any webpage 😄

Next, let’s identify the state in our application. The only pieces of data that maybe considered as state here are the filter selections. The other data, the product list would likely be passed down as props and are not mutated.

filterSelections is an object which contains the selected value for each of the filters in our page.

filterSelections = { 
  price: ..., 
    ages: ..., 
    brands: ...,
}

Since the Products component is the common parent that contains the components that need filterSelections (the Filters and ProductResults components), it would be the appropriate home for this state to live in.

The Filters component, after receiving the filterSelections as a prop, will pass down relevant filter values to each of its children.

class Filters extends React.Component {
  render() {
    return (
      <>
        <PriceFilter price={this.props.filterSelections.price} />
        <AgeFilter ages={this.props.filterSelections.ages} />
        <BrandFilter brands={this.props.filterSelections.brands} />
      </>
    );
  };
}

filterSelections will also be passed down into the ProductResults component so that the filters can be applied and only the relevant products are shown.

These filters can’t be just static controls, we need to them to update filterSelections as the customer adjusts the filters.

We’re passing down filterSelections as props to the filters and we know props are immutable in React. So where do we mutate filterSelections then? The answer to that would be the Products component as its the owner of filterSelections having it as its state.

Let’s go ahead and add a bunch of change handler functions so that any changes to the filter selections are propagated up to the Products component where the actual mutation happens.

Here’s the Products component.

class Products extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      filterSelections: {
        price: someInitialValue,
        ages: someInitialValue,
        brands: someInitialValue,
      }
    }
  }

  updateFilters = (newSelections) => {
    this.setState({
      filterSelections: newSelections
    })
  };

  render() {
    return(
      <>
        <Filters 
          filterSelections={this.state.filterSelections}
          selectionsChanged={this.updateFilters}
        />
        <Products filterSelections={this.state.filterSelections} />
      </> // React 16 Fragment Syntax - whoohoo!
    );
  }
}

And the Filters component.

class Filters extends React.Component {
  
  updatePriceFilter = (newValue) => {
    this.props.selectionsChanged({
      ...this.props.filterSelections,
      price: newValue
    })
  };

  updateAgeFilter = (newValue) => {
    this.props.selectionsChanged({
      ...this.props.filterSelections,
      ages: newValue
    })
  };

  updateBrandFilter = (newValue) => {
    this.props.selectionsChanged({
      ...this.props.filterSelections,
      brands: newValue
    })
  };
  
  render() {
    return (
      <>
        <PriceFilter 
          price={this.props.filterSelections.price} 
          priceChanged={this.updatePriceFilter} 
        />
        <AgeFilter 
          ages={this.props.filterSelections.ages} 
          agesChanged={this.updateAgeFilter} 
        />
        <BrandFilter 
          brands={this.props.filterSelections.brands} 
          brandsChanged={this.updateBrandFilter} 
        />
      </>
    );
  };
}

This is pretty straightforward and would work. But we’ve got a bunch of functions in the Filters component, all of which seem to be doing very similar things.

And if we add a new kind of filter in future, we’ll need to write yet another similar looking function in this component.

Currying to the rescue

This is where the trick comes in and it’s a popular & fancy sounding functional programming concept called currying.

Before talking about currying, I’d like to show you how it can help clean up our component. Take a look for yourself —

class Filters extends React.Component {
  
  updateSelections = (selectionType) => {
    return (newValue) => {
      this.props.selectionsChanged({
        ...this.props.selections,
        [selectionType]: newValue,  // new ES6 Syntax!! :)
      });
    }
  };

  render() {
    return (
      <>
        <PriceFilter 
          price={this.props.selections.price} 
          priceChanged={this.updateSelections('price')} 
        />
        <AgeFilter 
          ages={this.props.selections.ages} 
          agesChanged={this.updateSelections('ages')} 
        />
        <BrandFilter 
          brands={this.props.selections.brands} 
          brandsChanged={this.updateSelections('brands')} 
        />
      </>
    );
  };
}

Neat right? Now the updatedSelections function is said to be curried. For the functional programming aficionados out there, this is a pretty simple and straightforward concept. But for folks like me who’s always lived in the imperative & object oriented side of things, this was confusing to understand. So let’s unpack it.

You might have wondered when I said that the updatedSelections() function has been curried, what the “uncurried” version of this function would look like. Here’s how —

updateSelections = (selectionType, value) => {
  this.props.updateFilters({
    ...this.props.filterSelections,
    [selectionType]: newValue,
  });
}

If we were to use this instead of our curried version, we’d need to make each of the Filter component children call updateSelections themselves and thus having to make them aware of the attribute name in filterSelections that they need to update, which is too much coupling.

The alternative is to use a dedicated function for each of the Filter components which leads to a mess like we saw already.

Our solution is to curry this function.

What’s currying?

Currying is transforming a function f into a function f' which takes part of the arguments that f originally needed and would return another function which could take in rest of the arguments, returning the result of f or could be curried itself.

Concretely, take this simple add function,

add = (x, y) => x + y;

when curried, it becomes —

curriedAdd = (x) => { return (y) => { return x + y; }}

So instead of calling add(1, 2) we could call curriedAdd(1) which returns a new function, which we could subsequently call with the other argument of add, like curriedAdd(1)(2) and get the final result 3.

Technically calling, curriedAdd(x) is called “partial application”, as in, we’re applying only part of the arguments that the original function add(X, y) needed.

Currying a regular function let’s us perform partial application on it.

This is a naive toy example which does not have much utility.

Now if we go back to our original example —

updateSelections = (selectionType) => {
  return (newValue) => {
    this.props.selectionsChanged({
      ...this.props.filterSelections,
      [selectionType]: newValue,
    });
  }
};

we can see how partial applications of the updateSelections function —

updateSelections('ages');updateSelections('brands');updateSelections('price');

helped us clean up our component and reduce coupling. That’s currying 😃


Like all problems in software, this is not the only solution to this problem. Here’s an alternate solution —

class Filters extends React.Component {
  
  updateSelections = (selectionType, newValue) => {
    this.props.selectionsChanged({
      ...this.props.filterSelections,
      [selectionType]: newValue, 
    });
  };

  render() {
    return (
      <>
        <PriceFilter 
          price={this.props.selections.price} 
          priceChanged={(value) => this.updateSelections('price', value)} 
        />
        <AgeFilter 
          ages={this.props.selections.ages} 
          agesChanged={(value) => this.updateSelections('ages', value)} 
        />
        <BrandFilter 
          brands={this.props.selections.brands} 
          brandsChanged={(value) => this.updateSelections('brands', value)} 
        />
      </>
    );
  };
}

I hope you found this technique useful. If you’ve used currying in your JavaScript / React project, do share snippets in the comments below and also your other comments and feedback are welcome ❤.

Discover and read more posts from Steve Robinson
get started