Stonex — predictable simple state container
Tags: javascript, typescript, react, node
Published: 2019-05-23 10:42:16

Hi everyone! 🙂

I want to suggest [my library](https://github.com/acacode/stonex) which allows you to manage and store data better and simpler than other similar libraries.

**Stonex it is predictable state container** with React like syntax

Solution why I decided to create stonex was experience of working with another stonex like libraries where I didn’t like most approaches and I wished to create own solution. I was should to write too many of code for the creating structure similar with stonex module and also was needed to attach too many dependencies. And because of this I decided to create the stonex, which makes your front-end development more easily!


{% github acacode/stonex %}

Also [Stonex already have support of ReactJS!](https://github.com/acacode/react-stonex)

# Why Stonex ? 

In applications where data is shared among components (react, angularjs, vue, etc), it might be confusing to know where a state should live. Ideally, the data in a component should live in just one component. So sharing data among sibling components becomes more difficult.

![](https://media.giphy.com/media/KKtAZiNVEeU8/giphy.gif)

Let’s take a look at example of ReactJS component:

```jsx
class Login extends React.Component {
 
  changeForm = ({ target }) => {
   this.setState({ [target.name]: target.value })
  }
  
  render() {
   const { firstName, lastName } = this.state
    
   return (
     <div>
       <input value={firstName} name="firstName" onChange={this.changeForm} />
       <input value={lastName} name="lastName" onChange={this.changeForm} />
     </div>
   )
  }
  
}
```


What should I do if there need to display the state data of this component in completely different parts of the application? Of course, we can use Context API, but it will not be a universal and not quite flexible solution.

But what if we have the one stonex reactjs component which contains all necessary application data? In this way works Stonex so in this way send application data will not have any difficulties!

How it will looks with stonex solution:

```jsx
// login component
import { connect } from 'react-stonex'

const Login = ({ firstName, lastName, changeAuthData }) => (
 <div>
   <input value={firstName} onChange={e => this.changeAuthData('firstName', e.target.value)} />
   <input value={lastName} onChange={e => this.changeAuthData('lastName', e.target.value)} />
 </div>
)

export default connect((state, modules) => ({
  firstName: state.auth.firstName,
  lastName: state.auth.lastName,
  changeAuthData: modules.auth.changeAuthData,
}))(Login)


// somewhere in sidebar component
import { connect } from 'react-stonex'

const Sidebar = ({ firstName, lastName }) => (
 <div>
   <span>Hello, {firstName} {lastName}</span>
 </div>
)

export default connect((state, modules) => ({
  firstName: state.auth.firstName,
  lastName: state.auth.lastName,
}))(Sidebar)

```

As you see exchange application data between components has no difficulties. And let’s take a look at Stonex Auth module:

```js
export default {
  state: { firstName: '', lastName: '' }
  
  changeAuthData(name, value) {
    this.setState({
      ...this.state,
      [name]: value
    })
  }
}
```

Looks easy, isn’t it? 😁

# Deep dive into Stonex

![](https://media.giphy.com/media/l2Je6HrCWMzM635bW/giphy.gif)

Before at all you need to install stonex

```shell
npm i -S stonex
# or using yarn
yarn add stonex
```

Stonex currently have exports: `StonexStore`, `StonexModule`, `createStoreBinder`, `StateWorker`. *Last two exports more needed as middlewares.*


## [StonexStore](https://github.com/acacode/stonex#stonexstoresource-link)

That’s what link all your modules together and makes wonderful store container! 😉

> What is needed to me if I want to create a StonexStore instance?

Almost nothing, just only object with your modules! See example:

```js
// store.js

import { StonexStore } from 'stonex'
import modules from './modules'

const store = new StonexStore(modules)
```

`modules` should be an object with keys where key it is the name of your module and value it is the reference of StonexModule class (not only class, it could be just object, but about this written further). See example:

```js
// ./modules/index.js
import UsersModule from './UsersModule'
import AuthModule from './AuthModule'
import ModalsModule from './ModalsModule'

const modules = {
  users: UsersModule,
  auth: AuthModule,
  modals: ModalsModule
}

export default modules
```

If you want to add some middleware or override place where stonex works with state you can use additional argument of `StonexStore`. More about Stonex middlewares is [here](https://github.com/acacode/stonex#stateworkersource-link).

Here is example of how to add some modifier and custom state worker to the store

```js
// store.js

import { StonexStore } from 'stonex'
import modules from './modules'
  
import Logger from './modifiers/Logger'
import AppStateWorker from './common/AppStateWorker'

const storeConfiguration = {
  modifiers: [ // middlewares
    Logger
  ],
  stateWorker: AppStateWorker
}

const store = new StonexStore(modules, storeConfiguration)
```

## [StonexModule](https://github.com/acacode/stonex#stonexmodulesource-link)
Stonex module it is a special class/object which contains all information/actions linked with specific state. More about it is [here](https://github.com/acacode/stonex#stonexmodulesource-link).

How it looks:

```js
import { StonexModule } from 'stonex'

class UsersModule extends StonexModule {
  state = []
  addUser = user => this.setState([...this.state, user])
  removeAllUsers = () => this.resetState()
}


export default UsersModule
```

As I said earlier stonex modules can be the references on classes but it is not always. You can create a pure stonex module (*It is the same but looks easier*):

```js
// ./modules/index.js

// don't worry about context. It links when module attaching to the store!
// Also all methods (like 'this.setState' ) from StonexModule class automatic will been inherited
const pureModule = {
  state: {},
  addItem(item){
   this.setState({...this.state, [item.name]: item })
  }
}

const modules = {
  pureModule
}

export default modules
```
> Note: pure modules not supports arrow functions as properties.

# Conclusion

As I said this project is not ended, but already contains on NPM. I’m use it in my pet projects and soon will migrate some enterprise web project on stonex.

Currently I’m working on the covering code of unit tests and write documentation anywhere it is possible.

**Thanks for reading! I’m really hope that this article helps you.**

**Will be glad to see any contributions or questions about this project!** 🙂

Happy coding! 🌟✨🎉



### Extra inks
Sample project with react and stonex on Github [is here](https://github.com/js2me/react-stonex-webpack-scss-boilerplate)
NPM: [https://www.npmjs.com/package/stonex](https://www.npmjs.com/package/stonex)
GitHub: [https://github.com/acacode/stonex](https://github.com/acacode/stonex)

![](https://media.giphy.com/media/Ydvn0G7Agtk9G/giphy-downsized.gif)