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 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-tree-store

v0.2.2

Published

Simple state management for React

Downloads

49

Readme

Simple state management for React

A implementation of a sharable state with the observer pattern and without context API

This package provides you with a way to supply values to React components, a fine control on when to update the components and a architecture proposal for making this shared states scalable and testable. It uses the concept of trees to controll when the components should update by simple === comparision of values.

If you liked the concept of this project, feel welcomed to contribute with ideas or code improvements!


How to use

Step 1: Design your minimal shared state tree.

This is just a JSON valid object that represents what behaviors and data belongs together and needs to integrate with your React app, a shared state that we call store. In this example im using the idea of a e-commerce shopping cart.

export type CartState {
  open: boolean
  products: Product[]
  total: number
  summary: {
    tax: number
    discount: number
    shipping: number
    productsSubtotal: number
  }
}

Step 2: Instantiate your state tree.

Create a file store.ts in src/store/cart/.

const initialState: CartState = {
  open: false,
  products: [],
  summary: {
    tax: 0,
    discount: 0,
    shipping: 0,
    productsSubtotal: 0,
    total: 0
  }
}

const cartStore = Store(initialState)

Step 3: Connect to your components.

Consume the state tree fully or partially.

// component that is the core concept of the data
function CartComponent() {
    // when any "Store.update" gets called, render this component
    const cart = cartStore.useTree() // CartState

    ...
}
// component that represents the summary of purchase
function SummaryComponent() {
    // get only the specific path of data and renders only if changed,
    // in this case only if the "summary" object gets reassigned
    const summary = cartStore.useSubtree('summary') // CartState.summary

    ...
}
// component that represents the cart summary toggle button, it
// may change it style if open or not or display the total
function SummaryComponent() {
    // will only render if any of this two primitives changes
    const total = cartStore.useSubtree('summary.total') // number
    const open = cartStore.useSubtree('open') // boolean

    ...
}

Step 4: Create the actions

Declare the functions that mutates the state in src/store/cart/actions/<action name>.ts with this pattern:

function toggleCartOpen() {
    // first, get the state to mutate it
    const cart = cartStore.getTree() // CartState

    // the mutation logic
    cart.open = !cart.open

    // at last, batch a React update cicle.
    // any component with the hook "useTree" or 
    // "useSubtree('open')" will re-render
    cartStore.update()
}
function calculateTotal() {
    // first, get the state to mutate it
    const cart = cartStore.getTree() // CartState

    // 1st section, business logic encapsulated
    // compute total cost of selected products
    const productsSubtotal = _.sum(cart.products.map(x => x.price * x.quantity))
    // compute tax, 5%
    const tax = productsSubtotal * 0.05
    // compute total based on other values
    const total = Math.max(0,
        cart.summary.shipping
        + productsSubtotal
        + tax
        - cart.summary.discount
    )
    
    // 2nd section, defining where in the tree our observers should update
    // by reassignment
    cart.summary = {
        ...cart.summary,
        productsSubtotal,
        total,
        tax
    }

    // at last, batch a React update cicle.
    // any component with the hook "useTree" or 
    // "useSubtree(...)" with 'summary', 'productsSubtotal',
    // 'total' or 'tax' will re-render sice that was the objects that 
    // got either re-assigned or primitives that possibly changed
    cartStore.update()
}

This functions can be async and called anywhere, just be sure that you dont make infinite loops and you are good to go.


Testing

With jest is very easy to write unit tests for the actions, you need first to set the state with the desired initial values of the test, call the action, write the test suites and then reset the state with his default values to avoid bugs in the subsequential tests.

// configure initial state of the test, its based on the default initial state + test changes
const cart = cartStore.getTree()
cart.products = productsMockup // mocked list of products
cart.shipping = 10

// action to be tested
calculateTotal()

// test suites
test('Products Subtotal', () => {
  // 100 * 0.50 + 400 * 0.20 = 50 + 80
  expect(state.productsSubtotal).toBeCloseTo(130)
  expect(state.tax).toBeCloseTo(6.5) // 5% tax
});

test('Total', () => {
  // 130 + 6.5 + 10
  expect(state.total).toBeCloseTo(146.5)
});

cartStore.reset() // reset to initial state