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

redu

v1.0.1

Published

Simple application-level state management for React apps.

Downloads

256

Readme

Redu

Simple application-level state management for React apps.

 

What is it?

Redu brings React's component-level state management up to the application level.

As far as application-level state management solutions go, Redux is a simple solution. At least, that's the idea. The reality is that while action creators, actions, and reducers are simple, open-ended concepts, their implementations can become unwieldy, and often leaves us with a lot of boilerplate.

What is simple, is React's built-in component-level state management, where events trigger action functions, which in turn call setState, to update that component's state:

class Counter extends React.Component {
  constructor(props) {
      super(props);
      this.state = { value: 0 }; // initial state
      this.increment = this.increment.bind(this);
  }
  
  increment() { // action function, which calls this.setState
    this.setState(prevState => ({
        value: prevState.value + 1 // hooray, the state is updated!
    }));       
  }
  
  render() {
    return (
      <div>
        {this.state.value}
        <button onClick={this.increment}>+</button>
      </div>
    )
  }
}

No reducers, no string constants, just event => action function => setState.

Redu performs this exact same flow, but at the application level, where a single "store" component's state acts as your application-level state, and any of its descendant "subscriber" components may derive props from the store component's state and props, which can include action functions to request application-level state changes.

 

How does it work?

Redu is comprised of two functions: createStore(Component), and createSubscriber(Component, toProps).

Both functions take in a React.Component, and create and return wrapper components around them.

createStore(Component) creates and returns a StoreComponent. StoreComponents wrap your top-level component and manages the application-level state.

createSubscriber(Component, toProps) creates and returns a SubscriberComponent. SubscriberComponents can derive props directly out of the StoreComponent's state, props, and action functions via the toProps function, and pass them down to the components that they wrap.

With just these two concepts, you can keep your application state in a single StoreComponent, and any descendant components can "cut the line" to receive exactly what they need from that StoreComponent.

StoreComponents and SubscriberComponents are just regular React.Components themselves, so you get all the familiarity, freedom, and tooling that "vanilla" React provides, but with the powerful benefits of application-level state management.

Quickstart Example

Imagine an app with the following structure:

<ComponentA>
    <ComponentB>
        <ComponentC />
    </ComponentB>
</ComponentA>

We could create a StoreComponent like so:

import { createStore } from 'redu';

/**
* Wrap your top-most component (ComponentA) in a StoreComponent.
*/
const StoreComponent = createStore(ComponentA);
/**
* This is your application-level state. This will become the StoreComponent's state.
*/
StoreComponent.initialState = {
    greeting: 'Hello'
};
/**
* These are the actions you can perform to modify the StoreComponent's state.
*/
StoreComponent.actions = {
    changeGreeting() {
        
        this.setState({ greeting: 'Hola' });
    }
};
/**
* Here we are exporting the StoreComponent that wraps ComponentA, which will end up being mounted to the DOM.
*/
export default StoreComponent;

And have components subscribe to that store like so:

import { createSubscriber } from 'redu';
/**
* ComponentC, though three levels down from the StoreComponent, 
* will be able to utilize and even modify that StoreComponent's state via its derived props.
*/
function ComponentC(props) {
    return (
        <div>
            <p>{props.greeting} World!</p>
            <button onClick={props.changeGreeting}>Translate</button>
        </div>
    );
}
/**
* This is a function that can take in the StoreComponent's state, props, and actions,
* and derive and return an object that will be passed to ComponentC as props.
*/
const toProps = (storeState, storeProps, storeActions) => {
                   
    return {
        greeting: storeState.greeting,
        changeGreeting: storeActions.changeGreeting
    };
}

/**
* Here we are actually exporting a SubscriberComponent that wraps ComponentC, which will end up being used in place of ComponentC seamlessly.
*/
export default createSubscriber(ComponentC, toProps);

createSubscriber's first argument is ComponentC, the component you wish to wrap in a SubscriberComponent.

The second argument is the toProps function that is used to derive and return a single object based on the StoreComponent's state, props, and actions.

This object is then used by the SubscriberComponent to pass down to ComponentC as props. ComponentC is now able to use aspects of the application-level state (greeting), as well as request changes to that state (changeGreeting).

Note that, while we only chose to showcase ComponentC, we could create subscribers out of ComponentA or ComponentB as well, should they need to derive anything from the store.

 

What does Redu solve?

Problem #1: threading props down multiple levels

In the Quickstart Example, we had an app with the following structure:

<ComponentA>
    <ComponentB>
        <ComponentC />
    </ComponentB>
</ComponentA>

Without Redu, if ComponentC wanted to utilize props or state from the top-level component, ComponentA, you'd have to pass them down first to ComponentB, then to the ComponentC. Also, if you wanted to modify ComponentA's state from ComponentC, you'd have to pass down an action function in the same manner, so that ComponentC would be able to call it.

With Redu, the application-level state is stored in the StoreComponent which wraps ComponentA, and ComponentC gets wrapped in a SubscriberComponent, which can pass down anything to ComponentC that it needs from the StoreComponent as props, skipping the need to pass down anything to ComponentB:

<StoreComponent>
    <ComponentA>
        <ComponentB>
            <SubscriberComponent>
                <ComponentC />
            </SubscriberComponent>
        </ComponentB>
    </ComponentA>
</StoreComponent>

This same idea can be applied to any child component, regardless of how far down the tree they are.

Problem #2: Scattered application state

Redu can eliminate as much component-level state as you want, and combine them into a single application-level state object. Your descendant components can then pull out or modify whichever properties of this state that they wish.

Condensing your application's state into a single object can be beneficial for quickly understanding what your app does and how it does it, along with other bonuses like being able to serialize/save/deserialize your app state.

That said, there's nothing wrong with having component-level state. You have the freedom to choose what state should be application-level and what should be component-level.

Problem #3: Redux boilerplate

It's no secret that implementing a new stateful feature in Redux can be a chore. You create action creators, actions, and reducers, and if what you need to do is asynchronous, there are even more hoops to jump through.

With Redu, the process is almost exactly the same as creating a stateful feature in a single "vanilla" component, with the addition of implementing simple toProps functions to allow ancestor components to derive what they need out of the store as props.

 

Installation, API and more examples and concepts

Continue reading here.