DEV Community

Cover image for Stonex — predictable simple state container
Sergey S. Volkov
Sergey S. Volkov

Posted on • Updated on

Stonex — predictable simple state container

Hi everyone! 🙂

I want to suggest my library 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 logo js2me / stonex

💡 Simple state container for JavaScript/TypeScript applications 💡

stonex

🌀 State container for JavaScript/TypeScript applications 🌀️

Table of Contents

What is that ?
How to use
Documentation:
- Stonex Store
- Stonex Module
- StateWorker
- createStoreBinder
License

What is that ?

This is a simple and easy library for managing/storing data.
It allows you to store and manage data correctly, and also combine all business logic into separated Stonex modules.

Easily configurable, most things can be overridden if necessary.

As well as in other similar libraries, each Stonex module has its own state and actions. But, unlike other libraries, most of the Stonex features are provided "out of the box", for example, the creating asynchronous actions.

The syntax of the modules is almost identical to the syntax of the ReactJS component.

Also currently Stonex is supporting integrations with: ReactJS (react-stonex)

💡 How to use

1. Needs to install it:

  npm i -S stonex
  # or

Also Stonex already have support of ReactJS!

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.

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

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:

// 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:

export default {
  state: { firstName: '', lastName: '' }

  changeAuthData(name, value) {
    this.setState({
      ...this.state,
      [name]: value
    })
  }
}

Looks easy, isn’t it? 😁

Deep dive into Stonex

Before at all you need to install stonex

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

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:

// 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:

// ./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.

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

// 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

Stonex module it is a special class/object which contains all information/actions linked with specific state. More about it is here.

How it looks:

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):

// ./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
NPM: https://www.npmjs.com/package/stonex
GitHub: https://github.com/acacode/stonex

Latest comments (0)