Use the React Context API; without nested render prop fatigue.
Tags: react, redux, context, javascript
Published: 2019-03-08 17:15:52

---
title: Use the React Context API; without nested render prop fatigue.
published: true
description: Use react-adopt to compose multiple Context Consumers without getting scared of what your code editor looks like.
tags: react, redux, context, javascript
---

##EDIT: with React Hooks, you can just use useContext to do this with no pain, this article is rendered of little value now, so is the library. I haven't found myself needing this at all.

## A Little Context (lol)
Redux has been my home, will be my home for a lot of use cases. It's made life easy as a developer who's always had to single handedly manage projects of scale. But here's a myriad of use cases where you don't need Redux's magic or functionality. Sometimes you just need central state without prop drilling. I gave job interviews in the last year that required small take-home projects and I realised just how powerful the Context API can be when you don't need Redux/MobX et al. Only issue, Redux let me put everything in one place and elegantly select what I needed from it. With Consumers, I got stuck in situations where there were render props inside render props inside...you get the drift. If you're into functional programming, first thought in your mind is if only I could compose these. Let's look at some mildly problematic code to understand this.

```javascript
import React, { Fragment } from "react";
import { render } from "react-dom";
import { __, map, prop } from "ramda";

import Drawer from 'drawer-component-from-wherever';
import List from 'list-component-from-wherever';
import Title from 'title-component-from-wherever';


/*
    Note: the following is not the "right" way to initialise context values, you're
    supposed to use a Provider and pass a value prop to it. If the Consumer finds
    no matching parent Provider, only then it uses the arguments passed to
    createContext as the initial value. This is a hypothetical example,
    hence the shortcuts.
*/

const PoseContext = React.createContext('closed'); // is the drawer open or closed?
const CartContext = React.createContext([{
  ids: idsFromSomewhere,
  cartMap: objectFromSomewhereElse,
}]);

const App = () => (
  <PoseContext.Consumer>
    {pose => (
      <Drawer pose={pose}>
        <Title pose={pose}>Your Cart</Title>
        <CartContext.Consumer>
          {({ ids, cartMap }) => <List data={map(prop(__, cartMap), ids)} /> }
        </CartContext.Consumer>
      </Drawer>
    )}
  </PoseContext.Consumer>
);

render(<App />, document.getElementById('appRoot'));

```

Well, that doesn't look very ugly now. But imagine if instead of using ramda and offloading to another component, we had something like this in the CartContext's Consumer:

```javascript
<CartContext.Consumer>
  {({ ids, cartMap }) => (
    <Fragment>
      {ids.map((id) => {
        const product = cartMap[id];
        return (
          <CartItem onClick={clickHandler} key={id}>
            <Link route={`/products/${product.slug}/p/${product.id}`}>
              <a>{product.name}</a>
            </Link>
          </CartItem>
        );
      })}
    </Fragment>
  )}
</CartContext.Consumer>;
```

Now imagine this, but with another Consumer called CouponConsumer to inject the app's Coupon related state. I would be terrified to look at Cart.js even if the culprit was me from 2 months ago. Enough banter, let's now be true to the title of this post and propose a solution to make neat code.

## Adopting react-adopt (ok sorry no more)
### The tiny library that saves the day.
{% github pedronauck/react-adopt %}

```javascript
import { adopt } from 'react-adopt';

const CombinedContext = adopt({
  pose: <PoseContext.Consumer />,
  cart: <CartContext.Consumer />,
});

const App = () => (
  <CombinedContext>
    {({ pose, cart: { ids, cartMap } }) => (
      <Drawer pose={pose}>
        <Title pose={pose}>Your Cart</Title>
        <List data={map(prop(__, cartMap), ids)} />
      </Drawer>
    )}
  </CombinedContext>
);

```

Neat, isn't it? We were able to compose two render prop components into a single one, and we could do the same thing with three or four. While Context Consumers are a great demo for this, we can utilise this neat trick for all render prop components and make our code more understandable and organised.

I'm trying to make it a habit to write every week, follow me if you think you want more of these tiny tricks that I picked up along my front end journey.