Practical Patterns with React Easy State
Tags: react, javascript, webdev, state
Published: 2018-10-16 10:05:10

---
title: Practical Patterns with React Easy State
published: true
description: Demonstrating Stupid Simple JavaScript Patterns by Making a Beer Finder App with React Easy State
tags: react, javascript, webdev, state
canonical_url: https://medium.com/dailyjs/design-patterns-with-react-easy-state-830b927acc7c
cover_image: https://thepracticaldev.s3.amazonaws.com/i/zs3eucqsko5lqrcn4cku.png
---

React Easy State is a transparent reactive state management library with two functions and two accompanying rules.

1. Always wrap your components with `view()`.
2. Always wrap you state store objects with `store()`.

```jsx
import React from 'react'
import { store, view } from 'react-easy-state'

const counter = store({
  num: 0,
  incr: () => counter.num++
})

export default view(() =>
  <button onClick={counter.incr}>{counter.num}</button>
)
```

This is enough for it to automatically update your views when needed. It doesn’t matter how you structure or mutate your state stores, any syntactically valid code works.

*Don’t worry if you are not familiar with Easy State yet, you already know enough to go on. Alternatively, you can check it out [here](https://github.com/solkimicreb/react-easy-state).*

## State management and beers

Easy State doesn’t care about how you manage your state, it looks out for **any kind** of state mutations and updates the view when needed. This article is about state management patterns though. Patterns that are beautifully simple, but overshadowed by a myriad of opinionated libraries.

The next sections explore these patterns through a small app, which finds matching beers for your meal. I recommend you to [try it out](https://solkimicreb.github.io/react-easy-state/examples/beer-finder/build/) before you continue reading.

[![Edit beer-finder](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/beer-finder?codemirror=1&hidenavigation=1&module=%2Fsrc%2FappStore.js)

## Sharing global state between components

React’s `state` and `setState` are often enough for managing local state, but big projects tend to need more. Some information is better saved globally.

JavaScript objects are singletons and they can be shared between files with ES6 `import` and `export`. This makes them a perfect candidate for storing global state.

```jsx
import { store } from 'react-easy-state'

const appStore = store({
  beers: [],
  fetchBeers (filter) {
    appStore.isLoading = true
    appStore.beers = [{ name: 'Awesome Beer' }]
    appStore.isLoading = false
  }
})

export default appStore
```

> Notice how the `fetchBeers` method uses `appStore.beers` instead of `this.beers`. It is a neat trick, which makes object methods safe to be passed as callbacks.

Don’t worry about the dummy `fetchBeers` method yet, we will smarten it up later. The `appStore` can be imported and used in any file — like the below `NavBar` component.

```jsx
import React from 'react'
import { view } from 'react-easy-state'
import SearchBar from 'material-ui-search-bar'
import { LinearProgress } from 'material-ui/Progress'
import appStore from './appStore'

export default view(() =>
  <div className='searchbar'>
    <SearchBar onRequestSearch={appStore.fetchBeers} placeholder='Some food ...'/>
    {appStore.isLoading && <LinearProgress/>}
  </div>
)
```

We need another component to display the fetched beers. Naturally it also has to import the global `appStore` to map a view to its beers array.

```jsx
import React from 'react'
import { view } from 'react-easy-state'
import appStore from './appStore'
import Beer from './Beer'

export default view(() =>
  <div className='beerlist'>
    {!appStore.beers.length
      ? <h3>No matching beers found!</h3>
      : appStore.beers.map(beer => <Beer key={beer.name} {...beer }/>)
    }
  </div>
)
```

> Easy State re-renders the above `NavBar` and `BeerList` components when `appStore.isLoading` or `appStore.beers` changes.

## Async actions

Let’s breathe life into the `fetchBeers` method. There is not much to change: it should be turned into an async method and it should fetch the beers from an API, instead of faking them.

```jsx

import { store } from 'react-easy-state'
import * as api from './api'

const appStore = store({
  beers: [],
  async fetchBeers (filter) {
    appStore.isLoading = true
    appStore.beers = await api.fetchBeers(filter)
    appStore.isLoading = false
  }
})

export default appStore
```

An ideal store is only responsible of state manipulation and nothing else. Abstracting away the view related logic in the components and the networking logic in an API layer is a good practice. This could mean destructuring events in the component's event handlers and handling authentication and headers in a separate API layer.

Our API is a simple one. It has a single function, which fetches matching beers for a passed food.

```js
import axios from 'axios'

const api = axios.create({
  baseURL: 'https://api.punkapi.com/v2'
})

export async function fetchBeers (filter) {
  const { data } = await api.get('/beers', {
    params: { food: filter }
  })
  return data
}
```

> This example uses the [Punk API](https://punkapi.com/documentation/v2) to find beers. Check it out if you need some free data for your coding demos.

## Encapsulating local state

Global state is crucial for big applications, but local state can be just as handy: it improves project structure and reusability. It is your responsibility to decide when to use which.

We are still missing a Beer component, which could use some local state to switch between a picture and a description view. Putting a state store object on the component as a property is a simple way of implementing this.

```jsx

import React, { Component } from 'react'
import { view, store } from 'react-easy-state'
import Card, { CardContent, CardMedia } from 'material-ui/Card'

class Beer extends Component {
  store = store({ details: false })

  toggleDetails = () => this.store.details = !this.store.details

  render () {
    const { name, image_url, food_pairing, description } = this.props
    const { details } = this.store

    return (
      <Card onClick={this.toggleDetails} className='beer'>
        {!details && <CardMedia image={image_url} className='media'/>}
        <CardContent>
          <h3>{name}</h3>
          {details
            ? <p>{description}</p>
            : <ul>
                {food_pairing.map(food => <li key={food}>{food}</li>)}
              </ul>
            }
        </CardContent>
      </Card>
    )
  }
}

export default view(Beer)
```

> Easy State re-renders the `Beer` component whenever `store.details` changes. It doesn’t matter if it is a local store or a shared global one, you can even mix the two in a single component.

The `details` flag toggles between the two views of the beer card. It could also be stored on the beer object itself, but putting it in an isolated local store is a cleaner approach. It stores view related metadata, which should not pollute the real data.

## Conclusion

Npm is packed with amazing tools, which simplify front-end development by a huge amount. Never hesitate to use them when you need them, but always think before you install. Sometimes you can be more productive with less tools.

Some of you wouldn’t even call the above snippets patterns. They are just code examples, that most developers are familiar with. Still, they were more than enough for a creating small app.

*If this article captured your interest please help by sharing it. Also check out the [Easy State repo](https://github.com/solkimicreb/react-easy-state) and leave a star before you go.*

*Thank you!*
*(This article was originally published on [Medium](https://medium.com/dailyjs/design-patterns-with-react-easy-state-830b927acc7c))*