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

use42

v0.0.7

Published

Application state

Downloads

5

Readme

🖤 act0 - not a "redux"

Type-safe React application state library with zero setup. Powered by Object.defineProperty.

Quick start

npm i act0
# yarn add act0
import Act0 from 'act0';

// 1. Define your root store
// Act0 adds "use" method to the RootStore instance, that's all what it does
class RootStore extends Act0 {
  count: 1,
}

const store = new RootStore();

// 2. Use
export default () => {
  const count = store.use('count'); // same as store['count'] but reactive

  return (
    <div onClick={() => store.count++}>Clicks: {count}</div>
  );
}

Slow start

Create your store with ES6 classes extended by Act0. It's recommended to split it into multiple objects that I call "sub-stores". In the example below Users and Companies are sub-stores. Level of nesting is unlimited as for any other JavaScript object.

// store.ts
import Act0 from 'act0';

class Users extends Act0 {
  ids = [1, 2, 3];
  readonly loadUsers = () => fetch('/users')
}

class Companies extends Act0 {
  name = 'My Company';
}

class RootStore extends Act0 {
  readonly users = new Users();
  readonly companies = new Companies();
  readonly increment = () => this.count++;
  readonly decrement = () => this.count--;
  count = 0;
}

const store = new RootStore();

export default store;

Use readonly prefix to protect class members to be reassigned.

Use use method to access store object properties in your component.

const MyComponent = () => {
  const count = store.use('count');
  const ids = store.users.use('ids');
  const name = store.companies.use('ids');
  // ...

To change value, assign a new value.

store.count++;
store.users.ids = [...store.users.ids, 4]

Call methods for actions.

useEffect(() => {
  store.users.loadUsers().then(() => {
    store.decrement();
    // ...
  });
}, []); // no dependencies for methods

Pass values returned from use as dependencies for hooks.

const count = store.use('count');

const callback = useCallback(() => { console.log(count); }, [count])

You can split sub-stores into multiple files and access root store using first argument.

// ./store/index.ts
import Users from './Users';
import Companies from './Companies';

export class RootStore {
  readonly users: Users;
  readonly companies: Companies;
  constructor() {
    this.users = new Users(this);
    this.companies = new Companies(this);
  }
}
// ./store/Users.ts (Companies.ts is similar)
import type { RootStore } from '.'; // "import type" avoids circular errors with ESLint

export default class Users {
  #store: RootStore;
  constructor(store: RootStore) {
    this.#store = store;
  }
  readonly loadUsers() {
    // you have access to any part of the store
    const something = this.#store.companies.doSomething();
    // ...
  }
}

I recommend to destructure all methods that are going to be called to make it obvious and to write less code at hooks and components.

const MyComponent = ({ id }) => {
  const { increment, decrement, users: { loadUsers } } = store;
  // ...
}

or better

const { increment, decrement, users: { loadUsers } } = store;

const MyComponent = ({ id }) => {
  // ...
}

Act0.of

If you don't want to define class you can use this static method. Act0.of<T>(data?: T): Act0 & T returns Act0 instance with use method and uses firtst argument as initial values.

class RootStore extends Act0 {
  readonly coordinates = Act0.of({ x: 0, y: 100 });
  // ...

const MyComponent = () => {
  const x = store.coordinates.use('x');
  const y = store.coordinates.use('y');
  // ..
  // store.coordinates.x = 100;

You can also define custom record:

class RootStore extends Act0 {
  data: Act0.of<Record<string, Item>>();
  // ...
}

// ...

And acces values as usual:

const MyComponent = ({ id }) => {
  const item = store.data.use(id); // same as store.data[id] but reactive 
  // ...
  // store.data[id] = someValue; // triggers the component to re-render

For a very small app you can define your entire application state using Act0.of method (also exported as a constant).

// store.ts
import { of as act } from 'act0';

const store = act({
  count: 1,
  companies: act({
    name: 'My company',
    someMethod() { /* ... */ }
  }),
});

export default store;
import store from './store';

const MyComponent = () => {
  const count = store.use('count'); // same as store['count'] but reactive
  const name = store.companies.use('name'); // same as store.companies['name'] but reactive

  // store.companies.someMethod();