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

@m6web/normalizer

v2.0.1

Published

Data normalizer for JS objects, useful for your Redux reducers

Downloads

8

Readme

@m6web/normalizer

Continous Integration npm npm bundle size npm GitHub last commit NPM

JS Data normalizer used at Bedrock Streaming in our React frontend apps. Mainly designed and produced by @flepretre

Installation

yarn add -E @m6web/normalizer
npm install @m6web/normalizer

Much of application data is presented in the form of a list of entities. In general, it is assumed that these entities never change, which is usually the case.

During navigation, the application will retrieve new lists of entities. Among these new lists, some entities are already known. In order to avoid making useless returns, we have introduced the normalizer. Its role is to normalize the list of elements and not to replace the elements already known in our reducers. In other words, the normalizer allows us to ensure the immutability of our lists of entities while deleting the rerendering of elements already present in the page.

Architecture of a list of elements

The trick to avoid resending all the elements of a list is to store the list in two parts.

  • the list of ids of the elements of the list, sorted in the display order
  • an index containing all the elements, indexed by their id.

This data structure (plus the respect of immutability in the store) allows us to do two things. First, it is easy to know if the list display needs to be refreshed. If the list of ids has changed, the display must be refreshed, otherwise we do nothing. Secondly, it is easy to know if an item needs to be refreshed. If the object is different, then its display must be updated, otherwise nothing is done.

rerender

Here, if we use PureComponents, only red elements will trigger rerender.

Use normalize

Reducer

import { GET_ELEMENTS } from "./element.actions";
import Normalizer from "@m6web/normalizer";

export const initialState = {
  elementsById: {}, // Index of elements
  elementIds: [] // List of ids
};

// Init of normalizer
const normalizer = new Normalizer("elementIds", "elementsById");

export default (state = initialState, action) => {
  switch (action.type) {
    case GET_ELEMENTS: {
      return normalizer.set(state, action.data, action.serviceCode);
    }
    default: {
      return state;
    }
  }
};
  • The elementIds variable contains the current list of elements to display
  • The elementsById variable contains all the elements already retrieved, indexed by their id

Components

import React, { PureComponent } from "react";
import { connect } from "react-redux";

// Element
class Element extends PureComponent {
  render() {
    const { element } = this.props;

    return <li key={element.id}>{element.name}</li>;
  }
}

// List
const List = ({ elementsById, elementIds }) => (
  <ul>
    {elementIds.map(id => (
      <Element element={elementsById[id]} />
    ))}
  </ul>
);

// Connector
const mapStateToProps = ({ elements: { elementsById, elementIds } }) => ({
  elementsById,
  elementIds
});
export default connect(mapStateToProps)(List);

The element benefits from the shouldComponentUpdate of the PureComponent which does a shallowEquals on its props. The list is connected, so it benefits from the pure status of the connect of react-redux.

Advanced uses

The third parameter of the normalizer constructor is the index key. By default, it is 'id'.

The append method of the normalizer allows to add the ids of new elements to the list of ids. In other words, the ids of the elements present in the list of ids are not deleted contrary to the set method. The elements already present in the list of ids are ignored.

The append and set methods accept a second parameter. The latter allows to specify a path for the storage of ids.

It is possible to define a method via the shouldElementBeUpdated() function, which determines whether or not an element should be updated.

Example:

const programByFolderNormalizer = new Normalizer(
  "programIdByFolder",
  "simpleProgramsById"
).shouldElementBeUpdated(
  (element, newElement) =>
    element.parent_context.highlighted !== newElement.parent_context.highlighted
);