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

laco

v1.2.1

Published

Simple and powerful state management for React and Inferno

Downloads

5,811

Readme

Laco

npm version travis

Very simple and powerful state management solution for React and Inferno.

Set up your stores and subscribe to them. Easy as that!

Check out the introductory blog post.

npm install laco

npm install laco-inferno or npm install laco-react

Summary

  • :rocket: Simple to use
  • :tada: Lightweight (under 1kb in size)
  • :sparkles: Partial Redux DevTools Extension support (time travel)

Example

import { Store } from 'laco'
import { Subscribe } from 'laco-react' // or 'laco-inferno'

// Creating a new store with an initial state { count: 0 }
const CounterStore = new Store({ count: 0 })

// Implementing some actions to update the store
const increment = () => CounterStore.set((state) => ({ count: state.count + 1 }))
const decrement = () => CounterStore.set((state) => ({ count: state.count - 1 }))

const Counter = () => (
  <Subscribe to={[CounterStore]}>
    {(state) => (
      <div>
        <button onClick={decrement}>-</button>
        <span>{state.count}</span>
        <button onClick={increment}>+</button>
      </div>
    )}
  </Subscribe>
)

For more examples check the examples folder.

Following commands are available for each example project:

npm run start:dev

npm run start:prod

npm run test

Redux DevTools Extension

Check out Redux DevTools Extension.

Time travel

Just click on the stopwatch icon and you will get a slider which you can play with. That's it! :)

React Native Debugger

Check out React Native Debugger.

Time travel

Works as you would expect :)!

API

Store(initialState: Object, name?: String)

// Initializing a new store with an initial state and a name:
const NewStore = Store({ count: 0 }, "Counter")

The name is optional and is used to get an overview of action and store relationship in Redux DevTools Extension. Action names for the Store will now show up as Counter - ${actionType} in DevTools Extension where as before only ${actionType} was shown.

Store.get()

// Getting the state of the store
Store.get()

Returns an object which could be something like { count: 0 } following the example.

Store.set(state: Function, info?: String)

// Setting a new state and passing an optional action name "increment"
Store.set((state) => { count: state.count + 1 }, "increment")

Store.replace(state: Function, info?: String)

Immutability is taking care of to a certain extent behind the scenes with the spread operator with Store.set() but you might want more control over the state. You can do this by using Store.replace() like so:

// Setting a new state and passing an optional action name "increment"
Store.replace((state) => { /* return modified state */}, "increment")

Store.setCondition(condition: Function)

// Setting a condition to prevent count from going below 0
// and a special case for `SudoDecrement` action which CAN make count go below 0
CounterStore.setCondition((state, actiontype) => {
  if (state.count >= 0) {
    return state
  } else if (actionType === 'SudoDecrement') {
    return state
  }
  // Otherwise return nothing which does NOT change any state
})

Setting a condition on a store will make every Store.set() call go through the condition first.

Store.reset()

// Resets the store to initial state
Store.reset()

A good practice when testing is to call reset() on a store before using the store in a test. This takes care of some edge cases that you might run into. The reason for this is that Laco is using a global object behind the scenes to store all of your stores states into one big object. Redux also operates on one global object which makes time travel possible.

Store.dispatch(value: any, info: String)

// Dispatching an action that does not change the state of the store
Store.dispatch(changeLocation(), "Location change")

You might want to dispatch an action that is associated with a certain store but don't want to change the state. The action will in this case be shown as StoreName - Location change.

dispatch(value: any, info: String)

import { dispatch } from 'laco'

// Dispatching a global action that does not change any state
dispatch(changeLocation(), "Location change")

You might want to dispatch a global action that is NOT associated with any store. The action will in this case just be shown as Location change.

<Subscribe />

Props

  • to - Array of stores you want to subscribe to
<Subscribe to={[CounterStore]}>
  {({ count }) => (
    <div>
      <button onClick={decrement}>-</button>
      <span>{count}</span>
      <button onClick={increment}>+</button>
    </div>
  )}
</Subscribe>

The Subscribe component is making use of the new render prop idea. Related articles:

Testing

Testing using tape:

import * as test from 'tape'
import { CounterStore, increment, decrement } from './CounterStore'

test('counter', (t) => {
  CounterStore.reset()
  t.assert(CounterStore.get().count === 0);

  increment()
  t.assert(CounterStore.get().count === 1);

  decrement()
  t.assert(CounterStore.get().count === 0);

  t.end()
})

Credits

Heavily inspired by: