npm package: @polight/store
Description: Low-Tech & Future-Proof Store
Author: Vincent Agnano
Latest version: 0.1.2

# Application State Store

Store is a lightweight and flexible state management library for JavaScript applications, designed with compatibility in mind for Lego and other libraries/frameworks. It provides a simple and intuitive API to manage application state and facilitate communication between components.

A store is like a state for an entire app. Meaning that it holds the key/values
that are shared among the components of an app.

It is as **light** as **0.4Kb** 🪶

## Features

- Centralized store to manage application state
- Subscription-based model to listen for state changes
- Support for custom actions and mutations
- Compatibility with Lego and other libraries/frameworks

## Installating The Store

## Usage For a Lego App

It's an abstract class that you should implement:

_/my/custom/store.js_

```javascript
import { LegoStore } from './your/path/to-the/store.min.js'

const state = { count: 0 }

const actions = {
  increment() {
    this.setState({ count: this.state.count + 1 })
  }
}

// Describe the state of the store with defaults and the actions
const store = new LegoStore(state, actions)

// export the instance that will be shared across all your components
export default store
```

Now you can connect your Lego components to the store:

_/bricks/x-incrementer.html_

```html
<script>
  import store from '/my/custom/store.js'

  export default class extends Lego {
  init() {
    // Sync the current component with the `count` state.
    store.subscribe(this, ['count'])
  }

  increment() {
    console.info("x-incrementer button clicked")
    store.actions.increment()
  }
</script>

<template>
  <p :if="state.count == 0">No increment yet</p>
  <p :if="state.count > 1">Count is ${state.count}</p>

  <button @click="mySignInMethod">Do Increment</button>
</template>
```

## Usage For Non-Lego Apps

```javascript
import { AbstractStore } from './your/path/to-the/store.min.js'

class MyStore extends AbstractStore {
  notifyCall(target, props) {
    // implement here what should happen to "target" when a change occurs with the "props".
  }
}

// Describe the state of the store with defaults
const state = { count: 0 }

// List all common methods
const actions = {
  increment() {
    this.setState({ count: this.state.count + 1 })
  }
}

const store = new MyStore(state, actions)

export default store
```

You can now import that `store` and use it specifically to your needs.

## Usage

### Subscribing to State Changes

Components can subscribe to state changes by providing a render method that will be called whenever the state updates. Use the subscribe method to subscribe a component to the store:

```
store.subscribe(component, props)
```

- `component`: The component instance subscribing to the store.
- `props`: An array or object specifying the properties of the state that the component is interested in. Only these properties will be passed to the render method of the component when the state updates.

Example: `store.subscribe(this, ['user', 'currentItem'])` will notify `this` of the changes when the state change with the `user` and `currentItem` properties.

### Updating the State

To update the state, use the setState method:

```
store.setState(newState)
```

- `newState`: An object containing the updated state properties. The new state will be merged with the existing state, triggering the notification of subscribers.

Example: `store.setState({ user: { username: 'johndoe', password: 'secretpassword' }, currentItem: 'profile' })`

### Defining Custom Actions

You can define custom actions to perform specific operations or mutations on the state. Use the addAction method to register an action:

```
store.addAction(name, fn)
```

- `name`: A unique name for the action.
- `fn`: The action function to be invoked when the action is dispatched. The function has access to the store's state and methods for performing mutations or operations.

Example: `store.addAction('signIn', function(username, password) { … }`

### Dispatching Actions

To dispatch an action, use the dispatch method:

```
store.dispatch(actionName, ...payload)
```

- `actionName`: The name of the action to dispatch.
- `payload`: Optional data to be passed to the action function.

Example for a `signIn` action with 2 username and password attributes: `store.dispatch('signIn', 'johndoe', 'mysecretpassword')`

`dispatch` is implemented for confirmity with other Redux-like stores but calling an action can be done directly (see below).

### Calling an Action

Dispatching or calling an action behave the same way.
With the previous example you can also call a `signIn` action this way:

```
store.actions.signIn(username, password)
```

## Compatibility

This Store is designed to be compatible with Lego (https://lego.js.org) and other libraries/frameworks. Its lightweight nature and flexible API make it adaptable to different project requirements.