1.0.0 • Published 2 years ago

react-binding-context v1.0.0

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

react-lightning-context

A super performant lightning fast context library that only re-renders what has changed and nothing else. This library is a drop in replacement of the official React Context and it is only 12kb!!!!

Why ?

When building web apps at scale one of the main problems is performance over time. When you have 20+ multiple teams contributing to a same code base it is impossible to not hit this bottleneck. This library tries to mitigate some of this problem by providing a Context API that is reliant ant performant. It tries to avoid the un-necessary re-renders problem that the React Context has by only re-rendering what is upmost needed. As a result performance can be boosted dramatically.

This is NOT a state management library. Just a performant React Context replacement. You can also mix this up with redux for example and get a full redux experience but this is outside the scope of this library.

Libraries comparison

The bordered area is where the element is re-rendered. In the examples, the button is updating only one of the properties in the internal Context value.

Using react-lightning-contextUsing React Context
with gifwithout gif

How to install

  yarn add react-lightning-context

How to use it without Hooks

The main idea is following the same patterns and api that React Context provides with a little twist.

  const defaultValue = { valueA: { a: { b: 222, r: 333 } }, valueB: 222, valueC: 444 };
  const Context = createLightningContext(defaultValue);

  // `listenTo` can be (some examples):
  // - valueA -> { a: { b: 222, r: 333 } }
  // - valueA.a -> { b: 222, r: 333 }
  // - valueA.a.b -> 222

  const ExampleA = () => (
    <Context.Provider>
      <Context.Consumer listenTo={['valueC']}>
        {({ valueC }) => <label>{valueC}</label> }
      </Context.Consumer>
    </Context.Provider>);
};

What is going on here?

  • createLightningContext is creating the context.
  • Context.Provider is defining the area in which the context data is going to be shared.
  • Context.Consumer will listen to changes in the Context value and will re-rendered ONLY when the values on the listenTo prop in the context has changed. You can listen to more than one field, or you can go deep down into the props. ex: valueA.a.r.

How to use it with Hooks

The main idea ia following the same patterns and api that React Context provides with a little twist. This is doing the same as the previous example but with hooks.

  const defaultValue = { valueA: { a: { b: 222, r: 333 } }, valueB: 222, valueC: 444 };
  const Context = createLightningContext(defaultValue);

  const UseLightningContextHookComponent = () => {
    const { valueC } = useLightningContext({ listenTo: ['valueC'] }, Context);
    return <label>{valueC}</label>;
  };

  // `listenTo` can be (some examples):
  // - valueA -> { a: { b: 222, r: 333 } }
  // - valueA.a -> { b: 222, r: 333 }
  // - valueA.a.b -> 222

  const ExampleA = () => (
    <Context.Provider>
      <UseLightningContextHookComponent />
    </Context.Provider>);
};

What is going on here?

  • createLightningContext is creating the context.
  • Context.Provider is defining the area in which the context data is going to be shared.
  • useLightningContext will listen to changes in the Context value and will be updated ONLY when the values on the listenTo prop in the context has changed. You can listen to more than one field, or you can go deep down into the props. ex: valueA.a.r.

API Documentation

NameSupported ?Description
React.createContext renamed to createLightningContextYesIt is how we create the context we use createLightningContext instead of React.createContext
Context.ProviderYes
Class.contextTypeNo
Context.displayNameYes
Context.ConsumerYesA way of consuming a context value using components.
useContext renamed to useLightningContextYesA way of consuming a context value using hook. Similar to useContext
Context.MutatorNewA component that provides a way of mutating the value of the context
useLightningContextMutatorNewA Hook that provides a way of mutating the value of the context

createLightningContext

It follows a similar api that the React.Context provides. It only differs that we have a second parameter with configuration options.

ParametersTypesRequiredValues
First ParameterdefaultValueAnyYesThe default value to initialize the Context
Second ParameterOptionsObjectNo
Options.waitBeforeUpdateBooleanDefault: false. This helps when you have a very volatile Context value, that is constantly mutating. This helps by debouncing the updates so you can update the components less times having a similar effect with what concurrentMode will have.

It returns the Provider, Consumer, Mutator components

Example

const Context = createLightningContext({ value: 'test' });

const Context = createLightningContext({ value: 'test' }, { waitBeforeUpdate: true });

Context.Provider

This does not have any props. Same as React.Context it wraps the context experience.

Example

const Context = createLightningContext({ value: 'test' });

const TopLevelExperience = () => {
  return <Context.Provider>// ... your experience</Context.Provider>;
};

Context.Consumer

This need to be nested inside a Provider component. Same as React.Context it uses the function render pattern and it execution a function when it need to be render.

PropertiesTypeRequiredDescription
listenToArray< String >YesProperties from the Context.value that you want to listen to. It can be nested

It returns a function that is executed passing a mapped object with the binding

Example

const Context = createLightningContext({ value: { first: 1, second: 2 } });

const TopLevelExperience = () => {
  return <Context.Provider>
    <Context.Consumer listenTo={['value.first', 'value.seconds']}>
    {
      (values) => //... anything to render
    }
    </Context.Consumer>
  </Context.Provider>;
};

Return value example

if listenTo is ['value.first', 'value.seconds'] the render function that will execute is

  ({ 'value.first': 123, 'value.seconds': 333 }) => //...anything to render

useLightningContext

Same as Consumer but as a Hook api (similar to the useContext hook)

PropertiesTypeRequiredDescription
listenToArrayYesProperties from the Context.value that you want to listen to. It can be nested
ContextcreateLightningContext returned objectYesThe context you are using
const result = useLightningContext({ listenTo: [...] }, Context);

Context.Mutator

This need to be nested inside a Provider component. This is a component that provides a callback to update the internal context value. It uses the function render pattern and it execute a function when it need to be render passing the callback. No props are available.

It returns a function that is executed passing a callback function called setContextValue. This will updates the internal values and ONLY re-render what has changed and has someone listening.

Example calling setContextValue

The value parameter is the updated context value

setContextValue((value) => {
  return {
    ...value,
    ...yourChangeGoesHere,
  };
});

Example

const Context = createLightningContext({ value: { first: 1, second: 2 } });

const TopLevelExperience = () => {
  return <Context.Provider>
    <Context.Mutator>
      {
        ({ setContextValue }) => //... anything that want to use setContextValue
      }
    </Context.Mutator>
  </Context.Provider>;
};

useLightningContextMutator

Same as Context.Mutator but as a Hook.

PropertiesTypeRequiredDescription
ContextcreateLightningContext returned objectYesThe context you are using

Example

const setContextValue = useLightningContextMutator(Context);