Easy State Management on ReactJS with flatstore
Tags: react, javascript
Published: 2020-02-11 02:31:53

State Management is the biggest concern for any developer when starting a new app.  The few choices available (redux/mobx) are designed for enterprise-level development, where state management follows a strict pattern.  

Pfffft... Who needs all that for a quick prototype or medium sized application.  

Spoiler Alert!  I'm promoting my own state management library...

> [flatstore](https://github.com/joetex/flatstore) -- ReactJS state management at the speed of light.  Get/Set state from anywhere with component re-render. 

Feel free to send a pull request with all the files deleted.  Just kidding don't do that!

---

### Let's make a React app

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/kmas78ekswqs8s9cju22.PNG)

The example above shows dev.to articles with a random page button using the API 
https://dev.to/api/articles?page=1

The rest of this article will focus on building the simple app using flatstore.  We will build 4 files to put all of this together.
* DevAPI.js
* Articles.js
* Article.js
* PageWidget.js

This flatiron example and more can be found here
https://github.com/joetex/flatstore-examples

---

**DevAPI.js**
```react
import flatstore from 'flatstore';
import axios from 'axios';

flatstore.set("articles", []);
flatstore.set("page", 1);

export default async function apiDevArticles() {
    let randomPage = Math.floor(Math.random() * Math.floor(20)) + 1;
    flatstore.set("page", randomPage);

    try {
        let response = await axios.get('https://dev.to/api/articles?page=' + randomPage);
        flatstore.set("articles", response.data);
    }
    catch (err) {
        console.log(err);
    }
}
```

At the top, we define the default values using `flatstore.set`. 

A simple function then uses axios to GET request the dev.to API.  You no longer need to follow any programming patterns.  This API function can be created anywhere, but for organizational purposes, this was created in its own file.

The random page number is stored in `page`, and the API response (JSON Array) is stored to `articles` in the flatstore.  

---

**Articles.js**

```react
class Articles extends React.Component {
    constructor(props) {
        super(props);
        apiDevArticles();
    }
    render() {
        return (
            <div>
                <h2>dev.to Articles</h2>
                <PageWidget />
                {this.props.articles.map((article, index) => (
                    <Article id={index}></Article>
                ))}
            </div>
        );
    }
}
export default flatstore.connect(['articles'])(Articles);
```

This file calls the API in the constructor (or anywhere you want!), loops through all the articles, and renders an Article component passing the array index to **id** property which we will use soon. 

**flatstore.connect** is where we begin seeing how components can hook into the data.  It may have up to 3 parameters (example in *Article.js*):

1. An array of string keys to automatically watch from the store.
2. function onCustomWatched for generating the same array as #1 with code.
3. function onCustomProps for customizing the actual key/value stored in `this.props` of the component.  

The data is automatically stored into `this.props.articles` matching the key name used by both `apiDevArticles` and `flatstore.connect`.

---

**Article.js**

```react
class Article extends React.Component {
    render() {
        return (
            <div>
                <a href={this.props.url}>
                    <img src={this.props.social_image} width="75" />
                    <strong>{this.props.title}</strong>
                </a>
                <br />
                <span>{this.props.description}</span>
                <br /><br />
            </div>
        );
    }
}

let onCustomWatched = (ownProps) => {
    return ['articles-' + ownProps.id];
}
let onCustomProps = (key, value, store, ownProps) => {
    return { ...value }
}
export default flatstore.connect([], onCustomWatched, onCustomProps)(Article);
```

Now we can render each article.  

You'll notice `flatstore.connect` is using two new parameters that are callback functions.

**onCustomWatched** returns an array of store keys to watch, and using the components own properties for **id**, we can specify we only want to watch for articles[id] in the store, incase only that object changes. 

**Note:** You can drill down to a specific child of an array or object using the syntax `{object}-{key}` or `{array}-{index}`.  For example: `articles-1`, will return `articles[1]` from the store.  Or go crazy with something like `articles-1-tag_list-0`

**onCustomProps** is where you define the structure of the value that gets appended  into `this.props`.  In this example, we just spread all the article data into `this.props`, so it can be accessed like `this.props.title` or `this.props.description`.  


---


**PageWidget.js**

```react
class PageWidget extends React.Component {
    render() {
        return (
            <div>
                <button onClick={() => { apiDevArticles() }}>Random Page</button>
                <span>Page #{this.props.page}</span>
            </div>
        )
    }
}
export default flatstore.connect(["page"])(PageWidget);
```

Simple usage again.  Just watch the store for "page" changes, also call the API again when clicking the button.

---

Whew!  I hope that was simple... I spent more time writing this article than coding that react app.  

If you have any questions or suggestions to improve **[flatstore](https://github.com/joetex/flatstore)**, please feel free to leave a comment or send me a pull request.  

Enjoy!