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

@calvear/react-redux

v1.2.0

Published

Preconfigured Redux store initializer with Redux Saga, Redux Logger and Reselect for React SPA applications.

Downloads

12

Readme

React Redux

React library for eases Redux initialization for React SPA application. Is preconfigured and included helpful libraries as redux-logger and reselect.

Structure 📋

├── README.md
├── LICENCE.md
├── CHANGELOG.md
├── .vscode/ # vscode shared development config
├── src/
│   ├── effects/ # extra saga effects
│   ├── hooks/ # extra redux hooks
│   ├── reselect/ # reselect export bypass
│   ├── utils/ # action types utils
│   ├── middleware.js # middleware loader
│   ├── store.js # createStore
│   └── index.js
├── package.json
├── jsconfig.js
├── .babelrc
├── .eslintrc.json
└── .prettierrc.json
  • store.js: exports createStore wrapper function and StoreProvider.
  • middleware.js: initializes middleware, redux-logger.

How To Use 💡

Should be initialized with StoreProvider on App.jsx like:

import { StoreProvider } from '@calvear/react-redux';
import store from 'store';

export default function App() {
    return (
        <StoreProvider store={store}>
            <h1>Welcome to My App!</h1>
        </RouterProvider>
    );
}

So, you can create your first reducer, for example in store folder:

├── ...
├── store/
│   ├── sample/
│   │   │   ├── sample.partition.js # contains actions types and partition/store states
│   │   │   ├── sample.reducer.js # reducer
│   │   │   └── sample.saga.js # saga middleware
│   └── index.js # exports default store
├── App.jsx
└── index.js

Define your partition definition, containing partition key and actions types in sample.partition.js:

export default {
    // partition key
    Key: 'SAMPLE',

    // action types
    Type: {
        EXEC: 'EXEC',
        COMMIT: 'COMMIT',
        ROLLBACK: 'ROLLBACK',
    },

    // partition states
    State: {
        PREPARING: 'PREPARING',
        EXECUTING: 'EXECUTING',
        READY: 'READY',
        FAILED: 'FAILED',
    },
};

Define your reducer in sample.reducer.js:

import SamplePartition from './sample.partition';

export default function SampleReducer(store = {}, action) {
    const { type, payload } = action;

    switch (type) {
        // executes the action.
        case SamplePartition.Type.EXEC:
            return {
                ...store,
                state: SamplePartition.State.EXECUTING,
                data: payload,
            };

        // action is successful.
        case SamplePartition.Type.COMMIT:
            return {
                ...store,
                state: SamplePartition.State.READY,
            };

        // action was finished with errors.
        case SamplePartition.Type.ROLLBACK:
            return {
                ...store,
                state: SamplePartition.State.FAILED,
                error: payload,
            };

        // default doesn't changes the store,
        // so, components won't re-renders.
        default:
            return store;
    }
}

Finally (optional) your middleware saga in sample.saga.js:

import { all, call, dispatch, takeLatest } from '@calvear/react-redux/effects';
import SamplePartition from './sample.partition';
import Service from 'adapters/service';

function* exec({ payload }) {
    try {
        const data = yield call(Service.GetData);

        // Success action.
        yield dispatch(SamplePartition.Type.COMMIT, data);
    } catch (e) {
        yield dispatch(SamplePartition.Type.ROLLBACK, {
            stacktrace: e,
            message: 'Operation cannot be completed',
        });
    }
}

export default function* run() {
    yield all([
        // use all only if exists two or more listeners.
        takeLatest(SamplePartition.Type.EXEC, exec),
    ]);
}

Finally, your store/index.js file should looks like:

import { createStore } from '@calvear/react-redux';
import { SamplePartition, SampleReducer, SampleSaga } from './sample';

const reducers = {
    [SamplePartition.Key]: SampleReducer,
};

const sagas = [SampleSaga()];

export default createStore({ reducers, sagas, true });

Hooks

Library has custom hooks for eases partition handling.

  • usePartition: retrieves current partition state.
import { usePartition } from '@calvear/react-redux/hooks';
import { SamplePartition } from 'store/sample';

export default function MainPage()
{
    const { state, data, error } = usePartition(SamplePartition);

    ...
}
  • useActionDispatch: returns an action dispatcher.
import { useEffect } from 'react';
import { useActionDispatch } from '@calvear/react-redux/hooks';
import { SamplePartition } from 'store/sample';

export default function MainPage()
{
    const dispatchSampleExec = useActionDispatch(SamplePartition.Type.EXEC);

    useEffect(() =>
    {
        dispatchSampleExec({ someProp: 'hello world' });
    }, []);

    ...
}

Also, exports every hook from react-redux lib.

  • useSelector: extracts data from the Redux store state.
import { useSelector } from '@calvear/react-redux/hooks';
import { SamplePartition } from 'store/sample';

export default function MainPage()
{
    const state = useSelector(({ [SamplePartition.Key]: state }) => state);
    // in this example, will returns same that usePartition(...)

    ...
}
  • useDispatch: returns a store dispatcher.
import { useEffect } from 'react';
import { useDispatch } from '@calvear/react-redux/hooks';
import { SamplePartition } from 'store/sample';

export default function MainPage()
{
    const dispatch = useDispatch();

    useEffect(() =>
    {
        dispatch({
            type: SamplePartition.Type.EXEC,
            payload: { someProp: 'hello world' }
        });
        // in this example, will behaves like useActionDispatch(...)
    }, []);
    ...
}
  • useStore: returns a reference to the same Redux store.
import { useStore } from '@calvear/react-redux/hooks';

export default function MainPage()
{
    const store = useStore();

    const state = store.getState();

    ...
}

reselect

Library integrates and exports reselect lib.

  • createSelector: creates a memoized selector.
import { createPartitionSelector } from '@calvear/react-redux';
import { useSelector } from '@calvear/react-redux/hooks';
import { createSelector } from '@calvear/react-redux/reselect';
import { SamplePartition } from 'store/sample';

const sampleSelector = createPartitionSelector(SamplePartition);

const sampleDataSelector = createSelector(
    sampleSelector,
    sample => sample.data
)

export default function MainPage()
{
    const data = useSelector(sampleDataSelector);

    ...
}

Saga Effects

Library has custom redux-saga effects.

  • dispatch: dispatches an action with optional payload.
import { dispatch } from '@calvear/react-redux/effects';
import { SamplePartition } from 'store/sample';

function* exec({ payload })
{
    // dispatches COMMIT action
    yield dispatch(
        SamplePartition.Type.COMMIT,
        payload
    );
}

...
  • selectPartition: extracts partition from Redux state.
import { selectPartition } from '@calvear/react-redux/effects';
import { SamplePartition } from 'store/sample';

function* exec()
{
    // extracts sample state from store
    const { state, data, error } = yield selectPartition(SamplePartition);
}

...
  • takeAny: waits for any action type to occur n times.
import { takeAny } from '@calvear/react-redux/effects';
import { SamplePartition } from 'store/sample';

function* exec()
{
    // waits for any EXEC or COMMIT action,
    // intercepting two of these dispatches
    const [
        firstResult,
        secondResult
    ] = yield takeAny([
        SamplePartition.Type.EXEC,
        SamplePartition.Type.COMMIT
    ], 2);
}

...

Avoid actions types collision

Redux doesn't handles action types collision for reducers, so, for example if we has two partitions/reducers with same actions (EXEC, COMMIT), will conflicts dispatching any of these.

This library provides of a utility for prefix partition key to every action type.

import { packagePartitionHandler } from '@calvear/react-redux/utils';

let SamplePartition = {
    // partition key
    Key: 'SAMPLE',

    // action types
    Type: {
        EXEC: 'EXEC',
        COMMIT: 'COMMIT',
        ROLLBACK: 'ROLLBACK',
    },

    ...
};

// prefixes action types with partition key
export default packagePartitionHandler(SamplePartition);

Linting 🧿

Project uses ESLint, for code formatting and code styling normalizing.

  • eslint: JavaScript and React linter with Airbnb React base config and some other additions.
  • prettier: optional Prettier config.

For correct interpretation of linters, is recommended to use Visual Studio Code as IDE and install the plugins in .vscode folder at 'extensions.json', as well as use the config provided in 'settings.json'

Changelog 📄

For last changes see CHANGELOG.md file for details.

Built with 🛠️

  • React - the most fabulous JavaScript framework.
  • Redux - most popular frontend state handler.
  • React Redux - perfect React Redux integration.
  • Redux Saga - powerfull Redux middleware.
  • Redux Logger - impressive logger for Redux actions.
  • reselect - redux memoized selectors library.

License 📄

This project is licensed under the MIT License - see LICENSE.md file for details.


⌨ by Alvear Candia, Cristopher Alejandro