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

enty-react

v0.1.0

Published

React bindings for managing state with enty schemas

Downloads

7

Readme

Enty

enty npm enty circle

Introduction

Enty is a framework for managing data requested from back-ends and APIs. Instead of you manually storing requested data, Enty uses schemas to describe relationships and stores the data as normalized entities.

  • Views can declare what data they need.
  • There is practically no data fetching code.
  • Data given to views is always up to date.
  • Bad relationships in data become clear.
  • pairs wonderfully with graphql

Purpose

Any webapp that involves both a back and a front end will create entities. Unique pieces of data that are known by an id. The back end might call them models, the front end might call them application state, let's call them entities.

When the client side thinks of storing these entities in terms of endpoints and stores (or even actions and reducers) it's another set of hands touching the data. It allows more places for shady hacks to creep in. It allows more places for code to become brittle. It allows more places for the code to break.

On top of this you force the front end to recreate relationships between entities. Storing data by type in isolated stores logically makes sense, but when a view visually combines two entities (post with comments) you create a point where the front end needs to know exactly how to reconstruct this. This is not an insurmountable problem but as the code base grows so will the places where the front end has to know some specific detail and the places where things can go wrong.

In reality the front end doesn't care where the data came from or how it is stored. It just knows that it wants a certain number of entities and information about whether they have arrived yet.

Enty lets you describe the relationships of your entities through schemas. It is then able to store them in a normalized state. This means that they are not stored by request but by the unique id that they were given by the back-end.

Getting Started

Enty has two parts: A Schema and an EntityApi.

1. Schema

The first step in implementing Enty is to define your schema. This defines what relationships your entities have. A user might have a list of friends which are also users. So we can define that as a user

// entity/ApplicationSchema.js
import {
    MapSchema,
    ListSchema,
    EntitySchema,
} from 'enty';

var user = EntitySchema('user');
var userList = ListSchema(user);

user.define(MapSchema({
    friendList: userList
}))

export default MapSchema({
   user,
   userList
});

2. API

The second thing we need to do is to create our EntityApi from our schema;

// entity/EntityApi.js
import {EntityApi} from 'enty';
import ApplicationSchema from './ApplicationSchema';

const Api = EntityApi(ApplicationSchema, {
    core: payload => request('/graphql', payload)
});

export const {
    EntityStore,
    CoreQueryHock,
    CoreMutationHock,
} = Api;

3. Connect to react

// client.jsx
import {React} from 'react';
import {Provider} from 'react-redux';
import ReactDOM from 'react-dom';
import {EntityStore} from './entity/EntityApi';


ReactDOM.render(
    <Provider store={EntityStore}>
        <App />
    </Provider>,
    document.getElementById('app'),
);

4. Make a Query

// component/User.jsx
import {React} from 'react';
import {CoreQueryHock} from '../entity/EntityApi';

function User(props) {
    const {user} = props;
    return <img src={user.get('avatar')} />;
}

const withData = CoreQueryHock(props => {
    return {
        query: UserDataQuery,
        variables: {
            id: props.id
        }
    };
}, ['id']);

export default withData(User);

Entity Flow

  1. Props Change / OnMutate Triggered
    The Enty data flow begins when either a QueryHocked components props change or a MutationHocked component fires its onMutate callback. When this happens the corresponding promise creator in the API is fired.

  2. Data Request / Recieve
    The data request actions is triggered and the corresponding queryRequestState becomes a FetchingState. If the promise rejects the Error action is triggered, the requestState becomes an error and the flow finishes. If the promise resolves the receive action is triggered, the requestState becomes a SuccessState.

  3. Normalize
    The payload is passed into schema.normalize, which will in turn call schema.normalize recursively on its children as defined. Entities are stored under their schema type key and the result of their id attribute. Each entity is also passed through their constructor function which is given the current entity and the previous version if it exists.

  4. Results & Entities Stored
    The normalised entities are shallow merged with the previous state. The normalised result object is stored under its resultKey.

  5. Views Updated
    The update in state triggers a rerender. All hocked views select their data based on their result key. Schema.denormalize is given the new entity state and the normalised result object that matches their result key. As the result object is traversed denormalizeFilter is called on each entity. Any that fail the test will not be returned.

Entity Types

FAQ

What if I am using two Query/Mutation hocks

Use the options override!

const withQuery = CoreQueryHock(
    props => ({
        query: UserQuery, 
        variables: {
            id: props.id
        }
    }),
    {
        queryRequestStateProp: 'userRequestState'
    }
);

How do I load things?

Why is react-redux a peer dependency (it's not yet... but it should be)

How do I handle endpoints that return arrays?

We have found the cleanest way is to add a new service to your api and modify the data before it is given to Enty

// EntityApi.js
const Api = EntityApi(ApplicationSchema, {
    core: payload => request('/graphql', payload),
    userList: payload => request('/user', payload).then(data => ({userList: data}))
});

Do I have to export an MapSchema from my EntityApi?