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

react-providers

v2.0.2

Published

Library for creating your own business logic using react.context

Downloads

84

Readme

react-providers

React-providers is a library which helps you to work and manage React.Context components. The library offers you:

  • simple syntax with HOC components like react-redux.connect;
  • the single location to place your context models;
  • to implement your own business logic in contexts using familiar React components and react-lifecycle methods;
  • an easy way to include another context when it became required;
  • to work with dependencies between your contexts. So you should just describe dependencies and react-providers will build a correct hierarchy for you. You can see comments example to get more information about managing dependencies;
  • working both in server and client
  • this library depends only on hoist-non-react-statics, so you wouldn't get a lot of npm modules after installing.

Contents

Demo

Here is several examples: https://xnimorz.github.io/react-providers/

Install

yarn add react-providers

or

npm install --save react-providers

Usage step by step

This library can work in two mods:

  1. Use only HOC for Context
  2. Create the store with lots of context components

Let's see how to use library in both ways

Using only a HOC for context

  1. Implement your own React.Component using React.Context or just using React.Context:
export const TodosContext = React.createContext(['Do some work', 'Close task in jira']);
  1. Connect to this context using HOC use:
import { TodosContext } from './path/to/TodosContext';

function MyComponent({ todos }) {
  console.log(todos); // ['Do some work', 'Close task in jira']
}

export default use({ todos: TodosContext })(MyComponent);

Working with the store and connect to it

Step 1: Create your context React component:

Implement your own React.Component using React.Context:

https://github.com/xnimorz/react-providers/blob/master/examples/src/models/todoMVC/todos.js — in this file we use React lifecycle methods to store updates in localStorage.

import React from 'react';

const TodosContext = React.createContext();
class TodosContextProvider extends React.Component {
  state = {
    list: lsData || [],
  };
  // We can use React lifecycle methods to organise our work!
  componentDidUpdate() {}

  // You can get access to the methods from context consumer
  // This methods like reducers in Redux changes the state of the application but using React api
  add = (todo) => {
    this.setState((state) => ({
        list: [
          ...state.list,
          { id: 1 + Math.max(0, ...state.list.map((todo) => todo.id)), text: todo, completed: false },
        ],
      },
    }));
  };

  render() {
    // describe data that will be Context.Provider value (we can use here memoization, or move it to state to avoid unnecessary rerenders)
    const value = {
      // our data
      data: this.state,
      // our methods
      add: this.add,
    };

    // Provide value to consumer
    return <TodosContext.Provider value={value}>{this.props.children}</TodosContext.Provider>;
  }
}

// Each module should provide 2 components — Consumer and Provider
export default {
  Consumer: TodosContext.Consumer,
  Provider: TodosContextProvider,
};

Step 2: Add the context to react-providers.AppProvider:

Then, you can add your providers to the AppProvider:

import React from 'react';
import reactDOM from 'react-dom';
import { AppProvider } from 'react-providers';
import todos from './path/to/todos';

reactDOM.render(
  <AppProvider contexts={{ todos }}>
    <Example>
      YourApplicationIsHere
    </Example>
  <AppProvider/>
);

Step 3: Getting access to data from the context

We can use use HOC to get access to data that we store with AppProvider component:

import React from 'react';
import { use } from 'react-providers';
import todos from './path/to/todos';

class Example extends React.Component {
  componentDidMount() {
    // We'll get access to methods
    this.props.todos.add('New todo');
  }
  render() {
    // And data
    console.log(this.props.todos.data.list); // first time we'll get [], and second time [{id: 1, text: 'New todo', completed: false}]
    return 'SomeData';
  }
}

export default use({ todos })(Example);

See more examples here: https://xnimorz.github.io/react-providers/

Step 4 (optional): create context which depends on another context

AppProvider automatically builds correct Context tree that resolves dependencies between contexts. To get access from one context to another you can use use HOC:

import React from 'react';
import { AppProvider, use } from 'react-providers';

const A = React.createContext({});
class AProvider extends React.Component<{}, { data: string }> {
  state: Readonly<{ data: string }> = {
    data: 'A Context',
  };

  render() {
    return <A.Provider value={this.state}>{this.props.children}</A.Provider>;
  }
}

const aContext: IContext = {
  Consumer: A.Consumer,
  Provider: AProvider,
};

const B = React.createContext({});
class BProvider extends React.Component<{}, { data: string }> {
  state: Readonly<{ data: string }> = {
    data: 'B Context',
  };

  render() {
    console.log(this.props.a.data); // 'A Context'

    return <B.Provider value={this.state}>{this.props.children}</B.Provider>;
  }
}

const bContext: IContext = {
  Consumer: B.Consumer,
  // Describe BContext depends on AContext
  Provider: use('a')(BProvider),
};

ReactDOM.render(<AppProvider contexts={{ a: aContext, b: bContext }} />);

Developer experience

Why I should use react-providers instead of plain react.Context?

  1. The centralised place to store and manage our logic

You can store your context in one place where you paste AppProvider component (as a rule, it's better to put it at the beginning of React tree). You won't spend the time to manage dependencies between components. it's enough to declare dependency using use HOC in Providers (like in examples above). You have only one limitation — cyclic dependencies aren't allowed.

  1. Reduce code wrapping

As a rule, each model, which presented by React.Context component, should have only a single responsibility (SOLID principles). In our React components, we often want to get data from several Consumers. In such cases our code would be:

function YourComponent() {
  return (
    <UsersConsumer>
      {(users) =>
        <TopicsConsumer>
          {(topics) =>
            <CommentsConsumer>{(comments) => /*Your data*/ }</CommentsConsumer>
          }
        </TopicsConsumer>
      }
    </UsersConsumer>
  );
}
export default YourComponent;

Let's compare this example to the same example with react-providers lib:

function YourComponent() {
  const { users, topics, comments } = this.props;
  return (/*Your data*/);
}
// 1) connection using Object:
export default use({
  users: UserContext,
  topics: TopicsContext,
  comments: CommentsContext
})(YourComponent)));
// 2) or using array:
export default use('users', 'topics', 'comments')(YourComponent)));

We encapsulated all consumers' logic to our HOC component use. In component, we paid attention to How our component should work and what data it should return.

About react-providers pros

React-providers works with React.Context and offers you an easy way to combine and to store Contexts in one place. You work with familiar Components state. It hasn't any additional boilerplate code. React-providers manage your dependencies between contexts, so you don't mind about the right order of contexts in React components tree. HOC use allows you to describe dependencies using objects, arrays or string.

About redux

Redux (https://github.com/reduxjs/redux) is a great library that offers you time traveling and to store all application data in one place. It uses actions to describe what happens in application and reducers to implement the data logic of your application. To implement async action creators we can use our own middleware or existed middleware like redux-saga or redux-thunk. Redux offers us a great and pretty clear API to build our applications. But we'll have lots of boilerplate code to describe all actions, reducers etc. If you create not a too big application you probably don't need redux.

How to work without redux and any other library. Just using react

On the other hand, you probably don't need redux. Our React components can work without redux. And they do work. We can implement a method addTodo to the React component called Todos, which adds a new todo to the list that stored in the component state. Then we can transfer this addTodo method as a prop to other components. By this way, components can call addTodo. In described case addTodo calls this.setState method to set a new state to our Todos React component. addTodo implements the reducer pattern in our application. So addTodo is pretty similar to reducers in Redux. Moreover, react.lifecycle methods offer you to implement middlewares logic in react. You can add you own logic to componentDidMount, DidUpdate etc. methods. Consequently, we can work using only React API and React boilerplates to implement both view and business logic, because React already has methods that you need to implement your business logic.

Let's have a look at the way how we can work without redux:

  1. We can implement our business or async logic locally using React components. To transfer data from one component to another we can use props.
  2. When or if this logic becomes necessary in several places in our application we can move it to React Context.
  3. When one context depends on another context we can decompose them and place them in the correct order in React components tree.

OR

When we realize the logic becomes necessary in several places in our app we can move it to React Context and put it to react-providers.AppProvider component. And now we won't mind about where we should add Consumer for context. We just use use HOC where we need like react-redux.connect.

Dependencies resolver

This library resolves automatically dependencies between Providers. It means you can create two contexts AContext and BContext. BContext can depend on AContext, and the application will work correctly.

The main limitation is you should create cyclic dependencies. e.g. BContext can depend on AContext, but AContext can't depend on BContext simultaneously.

License

MIT License