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 🙏

© 2025 – Pkg Stats / Ryan Hefner

app-data

v1.0.0

Published

A file-system based state management library for React that uses convention over configuration to eliminate boilerplate.

Downloads

10

Readme

app-data (aka context-auto)

A file-system based state management library for React that uses convention over configuration to eliminate boilerplate.

Overview

context-auto is a unique state management solution that leverages your project's directory structure to automatically create and wire up state slices, actions, and reducers. Built on React's Context API, it provides a powerful and intuitive developer experience with zero boilerplate.

Features

  • Zero Boilerplate: No action types, action creators, or manual store configuration
  • File-System Based: Your folder structure defines your state shape and actions
  • Immutable State: State exposed via Proxy to prevent accidental mutations
  • First-Class Async Support: Built-in handling for async operations with automatic loading states
  • Lazy Loading: Support for on-demand data fetching
  • TypeScript Ready: Full TypeScript support (if applicable)
  • Developer Friendly: Intuitive API that feels natural to use

Quick Start

1. Setup the Provider

Wrap your app with the StateProvider:

// src/App.js
import React from 'react';
import { StateProvider } from 'app-data';
import MyComponent from './MyComponent';

function App() {
  return (
    <StateProvider>
      <MyComponent />
    </StateProvider>
  );
}

export default App;

2. Create Your State Structure

Organize your state using folders. Each folder represents a state slice:

/src
  /store
    /user
      INDEX.js      # Initial state & reducer
      login.js      # Synchronous action
      fetchProfile.js # Async action
    /cart
      INDEX.js      # Initial state & reducer
      addItem.js    # Synchronous action
      checkout.js   # Async action

3. Use in Components

import useStore from 'app-data';

function MyComponent() {
  const store = useStore();
  
  // Access state
  const user = store.user;
  
  // Call actions
  const handleLogin = () => {
    store.user.login({ username: 'john' });
  };
  
  // Check async loading states
  const isLoading = store.user.loading.fetchProfile;
  
  return (
    <div>
      <h1>Welcome {user.name}</h1>
      {isLoading && <span>Loading...</span>}
      <button onClick={handleLogin}>Login</button>
    </div>
  );
}

File Conventions

INDEX.js - Initial State

Each state slice must have an INDEX.js file that exports a default function returning the initial state:

// store/user/INDEX.js
export default function() {
  return {
    name: '',
    email: '',
    isAuthenticated: false
  };
}

Action Files

Synchronous Actions

Export a single default function that receives the current state and payload:

// store/user/login.js
export default function(state, payload) {
  return {
    ...state,
    name: payload.name,
    isAuthenticated: true
  };
}

Asynchronous Actions

Export four named functions to handle async lifecycle:

// store/user/fetchProfile.js
export function action(payload) {
  // Return a promise or undefined to cancel
  return fetch(`/api/user/${payload.id}`)
    .then(res => res.json());
}

export function pending(state, payload) {
  // State while loading
  return { ...state, loading: true };
}

export function fulfilled(state, payload, response) {
  // State on success
  return {
    ...state,
    ...response,
    loading: false
  };
}

export function rejected(state, payload, error) {
  // State on error
  return {
    ...state,
    error: error.message,
    loading: false
  };
}

Special Files

INIT.js - Startup Actions

Runs automatically when the app loads:

// store/user/INIT.js
export default async function() {
  const token = localStorage.getItem('token');
  if (token) {
    return await validateToken(token);
  }
}

DEFER.js - Lazy Loading

Fetches data the first time the state slice is accessed:

// store/products/DEFER.js
export default async function() {
  return await fetch('/api/products')
    .then(res => res.json());
}

Loading States

Async actions automatically track their loading state:

const store = useStore();

// Before action is called
store.user.loading.save // undefined

// During action
store.user.loading.save // true

// After success
store.user.loading.save // false

// After error
store.user.loading.save // Error object

// Clear loading state
store.user.save.clear();
// or
store.user.loading.save.clear();

Advanced Usage

Accessing Multiple State Slices

const store = useStore();
const { user, cart, products } = store;

Conditional Actions

const store = useStore();

if (!store.user.isAuthenticated) {
  store.user.login(credentials);
}

Error Handling

const store = useStore();
const error = store.user.loading.save;

if (error instanceof Error) {
  console.error('Save failed:', error.message);
  error.clear(); // Reset error state
}

API Reference

<StateProvider>

Wraps your app to provide state management.

useStore()

Hook that returns the store object with all state slices and actions.

State Slice Properties

  • Direct access to state values
  • .loading.[actionName] - Loading state for async actions
  • Action methods automatically attached

Action Methods

  • store.[slice].[action](payload) - Execute action
  • store.[slice].[action].clear() - Clear async action state

Best Practices

  1. Keep state slices focused and single-purpose
  2. Use INIT.js for authentication checks
  3. Use DEFER.js for expensive initial data loads
  4. Name actions descriptively (verb + noun)
  5. Handle errors gracefully in rejected functions

License

MIT