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

@rybr/redux

v2.3.6

Published

Simple state management Flux system for use with React and NodeJS

Downloads

124

Readme

Description

Simplified Redux like Flux implementation for React.
Works in both NodeJs and client side JS (React).
Works natively out of the box with NextJs.

redux.min.js is only 30kb

Uses Immer to enforce store immutability.
Uses React combined with React.memo to only trigger updates when specified store values have changed.

NOTE: This is still a work in progress

Installation

Browsers / <script>

// production
<script src="https://unpkg.com/@rybr/redux/dist/redux.min.js"></script>

// development
<script src="https://unpkg.com/@rybr/lenses/dist/redux.js"></script>

React / NextJs / NodeJs

npm install -D @rybr/redux

Terminology and Key Concepts

Stores

  • An Object that contains state information
  • Each Redux can contain multiple stores
  • Each store is identified by a unique Id that is bound to that store
  • Stores are READ ONLY and immutable. Attempting to modify the store or a value within the store outside of an action will throw an error.

Actions

  • Function that allows you to modify the stores.
  • actions are grouped under a store Id. This means you can have 2 actions with the same name but they are bound to different stores.
  • All actions have access to all stores and can modify any store but should ideally only modify the store that they are bound to

Picker Function

  • Function that pulls back specific values from the stores
  • Theses functions are uniquely bound to a listener
  • Has access to both the input props being sent to the React component as well as access to all stores

Listeners

  • Function that wraps a React component and listens for changes in the store(s)
  • Each listener must be provided a picker function that pulls values back from the stores and returns an Object that contains these values.
  • After every action, all listeners are called. Only the listeners whose picker function returned new values will trigger a re-render.

Epics

  • Function that has access to the current stores state information but cannot modify the store
  • Function call order is synchronized with actions. This guarantees that your epic function receives the latest store value
    • E.g. If you call an action and then try to access the store manually via Redux.getStore(), there is no guarantee that the action has finished running and has updated the store in time. Epics are queued with actions and the queue is run sychronously
  • Does not trigger listeners

Reducer

  • Instantiating a reducer will automatically create the store with initial state and bind the provided actions to it
  • Has the ability to call multiple actions in a row and only once all the batched actions are called will the listeners be notified that a change has occured

Usage

Either include the desired distribution script in the <head> or include the import in your React file.

#Browser
<script src="https://unpkg.com/@rybr/redux/dist/redux.min.js"></script>

#React
import Redux from '@rybr/redux'

Store initialization

By default there are no stores initialized.

The simplest way to initialize a store is to instantiate a Reducer. Alternatively, you can manually instiate stores using Redux.init(newStore) (note that this merges newStore into the current stores)

The main reason to use a Reducer is for simplicitly. It will also not try to re-instantiate the same store/actions if the file is reloaded or if the store already exists.

Manual Initialization

import Redux from '@rybr/redux'
import Reducer from '@rybr/redux/reducer'

const STORE_ID = 'storeOne'

Redux.init({
    //Optional initiale state for storeOne
    [STORE_ID]: {
        displayText: 'some default display text',
        shouldShow: true
    },
})

Redux.createActions(
    //store Id
    STORE_ID, 
    //All the actions bound to this tore
    {
        setDisplayText: (store, payload) => {
         store[STORE_ID].displayText = payload

            return store
        },
    }
)

Instantiating a Reducer

import Redux from '@rybr/redux'
import Reducer from '@rybr/redux/reducer'

const STORE_ID = 'storeOne'

const INITIAL_STATE = {
  displayText: 'some default display text',
  shouldShow: true,
  count: 0
}

export default new Reducer(Redux).init(
  //store Id
  STORE_ID,
  //All the actions bound to this tore
  {
    setDisplayText: (store, payload) => {
        store[STORE_ID].displayText = payload

        return store
    },
    setShouldShow: (store, payload) => {
        store[STORE_ID].shouldShow = payload

        return store
    },
    incCount: (store, payload) => {
        store[STORE_ID].count = store[STORE_ID].count + 1

        return store
    }
  },
  //Optional initiale state for storeOne
  INITIAL_STATE
)

A Reducer will provide a few utility functions:
Reducer.ID: The ID associated to this store
Reducer.Actions: A map of all actions boun to this store
Reducer.batchActions: function used to chain multiple actions in a row where only once the last action is called will the store be updated and trigger the listeners
Reducer.DelayedActions: To be used in conjunction with Reducer.batchActions.

Listening for Changes

In order to listen for changes, you must wrap your component in a listener and provide a picker function.

Whenever an action is called, once the stores are updated, all listeners will call their picker function which will pull back values from the stores. If any of those values change for a given listeners, then a re-render happens for that given component.

Create a listener function that binds to the current Redux

//listener.js

/*
NOTE: If you are using `NextJs` or if you are **NOT** including this package using a `<script>` tag in the header, you will most likely need to create this listener wrapper that binds your listener to the bundled es module.
*/

import Redux from '@rybr/redux'
import Listener from '@rybr/redux/listener'

Listener.bindRedux(Redux)

export default Listener.listen
//MyComponent.js

import React from 'react'

//If you included Redux globally via a <script> tag
import Listener from '@rybr/redux/listener'
//If you are only importing Reduxing into your JSX files
import Listener from './listener'

//Created using the Reducer
import myRedux from './myRedux.js'

const onHideClick = () => {
    myRedux.Actions.setShouldShow(false)
}

const onShowClick = () => {
    //Prevents 2 re-renders form occuring
    //Chains the actions (store is updated after each action is called)
    //Only once the last action is called are listeners notified of a change
    myRedux.batchActions(
        myRedux.DelayedActions.setShouldShow(true),
        myRedux.DelayedActions.incCount()
    )
}

export default listen(
    //This is the picker function.
    //First argument is the current store value
    //Second argument is any props passed into the component
    (store, props) => {
        //pull back specific values you want
        const { shouldShow, displayText } = store[myRedux.ID]

        //return a new object with the explicit values
        return {
            shouldShow,
            displayText
        }
    },
    //object returned from the picker function is passed 
    //into your React component function along with any props
    function MyComponent({ shouldShow, displayText, someOtherProp }) {
        return <div>
            {shouldShow ? <p>{displayText}</p> : null }
            <button onClick={onHideClick}>
                {'hide display text'}
            </button>
            <button onClick={onShowClick}>
                {'show display text'}
            </button>
        </div>
    }
)