npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

acey

v1.6.3

Published

### Acey aims to be for States what React is for Components - Easily **code decoupled** and **reusable** states for JS applications. - **Lightweight** but **highly customisable** so there is no need for external librairies/tools when handling states - Rob

Downloads

44

Readme

A robust, lightweight (~30kb), and portable object-oriented state manager

Object Oriented State Manager tailored for React {Native} ⚡

Acey aims to be for States what React is for Components

  • Easily code decoupled and reusable states for JS applications.
  • Lightweight but highly customisable so there is no need for external librairies/tools when handling states
  • Robust by a boilerplate free and class oriented architecture, so debugging is over. (no selectors, reducers, context, bindings, etc..)

Why Acey exists ?

As with most libraries, it started with the tiredness of repetitions. 💡

In December 2019, I was starting an umpteenth React-Native application and found myself coding the same states that I previously did in other apps. Reusability of components was easy with React, but I couldn't find any existing state manager that would make state reusability cool but that also combine oriented object programming and smooth management of cached data and local store. 📱

These were the 2 most important requirements for Acey:

  • States are built the same way you create Components and re-use them in each of your projects. 🖥️
  • Persistant so the states can be automatically synchronized with the local store and make your apps easily buildable in a no-network environment. 📡

Ways

Synchronise with local store

class User extends Model {
  constructor(state: any, options: any) {
    super(state, options);
  }
}

const myuser = new User({ id: 1, status: 'normal' }, {connected: true, key: 'user'});
myuser.setState({ status: 'good' })
//local store object: {}
myuser.setState({ status: 'great' }).store()
//local store object: {user: {id: 1, status: 'great'}}
myuser.setState({ status: 'perfect' }).store()
//local store object: {user: {id: 1, status: 'perfect'}}

/*
  Now when refreshing the page, the default state of my myuser will be: {id: 1, status: 'perfect'}
*/

Rendering on order

class User extends Model {
  constructor(state: any, options: any) {
    super(state, options);
  }
}
const myuser = new User({ id: 1, status: 'normal' });
myuser.setState({ status: 'good' }); //doesn't re-render components
myuser.setState({ status: 'great' }); //still doesn't re-render components
myuser.setState({ status: 'perfect' }).save(); //now it re-render components because the state's change has been saved

export default function App() {
   useAcey([ myuser ])
   
  /* state changed 3 times, but re-rendered once only */
  return (
    <div>
      <h1>{myuser.state.status}</h1>
    </div>
  );
}

Subscribe

class User extends Model {
  constructor(state: any, options: any) {
    super(state, options);
  }
}

const myuser = new User({ id: 1, status: 'normal' });
myuser.watch().state((prev, after) => alert(prev.status + after.status));
myuser.setState({ status: 'good' });
// alert: "normal good"
myuser.setState({ status: 'great' });
// alert: "good great"

Nested models

class Device extends Model {
  constructor(state: any, options: any) {
    super(state, options);
  }
}
class User extends Model {
  constructor(state: any, options: any) {
    super(state, options);
    this.setState({
    /* kids(): makes inherit the parent options */
      device: new Device(state.device, this.kids()),
    });
  }
  device = () => this.state.device;
}

const myuser = new User({
    id: 1,
    status: 'great',
    device: {
      platform: 'ios',
      version: 125,
    }
});
console.log(myuser.to().string()); // {"id":1,"status":"great","device":{"platform":"ios","version":125}}
myuser.device().setState({ platform: 'android', version: 200 });
console.log(myuser.to().string()); // {"id":1,"status":"great","device":{"platform":"android","version":200}}

Amazing for lists

class User extends Model {
  constructor(state: any, options: any) {
    super(state, options);
  }
}
class UserList extends Collection {
  constructor(state: any, options: any) {
    super(state, [User, UserList], options);
  }
}

const users = new UserList([], {});
users.append([
  { id: 1, name: 'bob' },
  { id: 2, name: 'alice' },
]);
//users = [{"id":1,"name":"bob"},{"id":2,"name":"alice"}]
const alice = users.find({ name: 'alice' });
//alice = {"id":2,"name":"alice"}
users.delete(alice);
//users = [{"id":1,"name":"bob"}]
users.push({ id: 3, name: 'mike' });
//users = [{"id":1,"name":"bob"},{"id":3,"name":"mike"}]
console.log(users.orderBy('id', 'desc'));
//print [{"id":3,"name":"mike"}, {"id":1,"name":"bob"}]

/*
...
and 40 more methods to ease your life.
*/

Quick implementations

1. Designless todolist in ReactJS

Try it online HERE (full app code in one single file)

2. A RESTful NodeJS API

Step 1/2 - State | ./todos.ts

import { Model, Collection } from 'acey'
import { v4 as uuid } from 'uuid'

export class TodoModel extends Model {
    constructor(initialState = {}, options){
        super(initialState, options)
    }
}

export class TodoCollection extends Collection {
    constructor(initialState = [], options){
        super(initialState, [TodoModel, TodoCollection], options)
    }
    orderByLastCreation = () => this.orderBy(['created_at'], ['desc'])
}

export default new TodoCollection([], {connected: true, key: 'todolist'})

Step 2/2 - Server | ./index.ts

import { config } from 'acey'
import LocalStorage from 'acey-node-store'
import todos from './todos'

const initServer = async () => {
    config.setStoreEngine(new LocalStorage('./db'))
    await config.done()
    return express()
}

initServer().then((server) => {
    console.log('Server started ')

    server.post('/', (req: express.Request, res: express.Response) => {
        todos.push({ id: uuid(), created_at: new Date(), content: req.body.content }).store()
        res.json(todos.last().to().plain())
    })
    
    server.delete('/:id', (req: express.Request, res: express.Response) => {
        todos.deleteBy({'id': req.params.id}).store()
        res.sendStatus(200)
    })
    
    server.get('/', (req: express.Request, res: express.Response) => {
        res.json(todos.orderByLastCreation().to().plain())
    })
    
    server.get('/:id', (req: express.Request, res: express.Response) => {
        const t = todos.find({id: req.params.id})
        t ? res.json(t.to().plain()) : res.sendStatus(404)
        
    })
    
    server.listen(PORT, err => {
        if (err) throw err
        console.log(`> Ready on http://localhost:${PORT}`)
    })
})

Try it yourself HERE

3. A React-Native micro-blogging app with Expi

Step 1/2 - State | ./post.ts

import { Model, Collection } from 'acey'
import moment from 'moment'

export class PostModel extends Model {

    constructor(initialState = {}, options){
        super(initialState, options)
    }

    ID = () => this.state.id
    content = () => this.state.content
    createdAt = () => this.state.created_at
    formatedCreationDate = () => moment(this.createdAt()).format("MMM Do");
}

export class PostCollection extends Collection {
    constructor(initialState = [], options){
        super(initialState, [PostModel, PostCollection], options)
    }

    sortByCreationDate = () => this.orderBy(['created_at'], ['desc'])
}

export default new PostCollection([], {connected: true, key: 'postlist'})

Step 2/2 - App

./App.js

//React imports
...

import { config } from 'acey'
import { useAcey } from 'react-acey'
import { posts } from './posts'

import Post from './src/components/post'
import AddPostInput from './src/components/add-post-input'

const App = () => {

  useAcey([ posts ])

  /* 
    save() method set the change state as done and re-render the required components
    store() save the new state in the local storage
  */
  const onSubmit = (content) => posts.push({id: randomID(), created_at: new Date(), content: content}).save().store()
  const onDelete = (post) => posts.delete(post).save().store()

  return (
    <>
      <ScrollView>
        <AddPostInput onSubmit={onSubmit} />
        {posts.sortByCreationDate().map((post) => {
          return (
            <View key={post.ID()}>
              <Post 
                content={post.content()}
                date={post.formatedCreationDate())}
                onDelete={onDelete}
              />
            </View>
          )
        })}
      </ScrollView>
    </>
  );
};

export default App;

Try it yourself HERE

Get Started

Usage

yarn add acey

To start the Acey engine, you need to declare the configuration as done at the root of your application. Here's how, according to your environment:

ReactJS

import { config } from 'acey' //HERE
config.done() //HERE

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

make sure to install react-acey to bind your React components with your Models and Collections.

yarn add react-acey

React-Native

At the root of your app, bind the React Native Store Engine (AsyncStorage) with Acey to benefit Acey's key features.

import AsyncStorage from '@react-native-community/async-storage'
import { config } from 'acey'

config.setStoreEngine(AsyncStorage)
config.done()

make sure to install and link async-storage .

yarn add @react-native-community/async-storage

NodeJS

After all your collections have been instanced:

  1. bind the Acey Store Engine for Node with acey-node-store
  2. And set the config as done.
import NodeStorage from 'acey-node-store'
import { config } from 'acey'
import MyCollection1 from './my-collection-1'
import MyCollection2 from './my-collection-2'
...

const myCollect1 = new MyCollection1([], {connected: true, key: 'collection-1'})
const myCollect2 = new MyCollection2([], {connected: true, key: 'collection-2'})
...

config.setStoreEngine(NodeStorage)
config.done()

make sure to install acey-node-store .

yarn add acey-node-store

Advanced demonstrations/system explainations

1. hydrate vs setState and Model nesting. Click here

2. Model's local storage cycle exlained. Click here