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

ember-redux-data

v0.0.4

Published

Redux-flavored data-layer for use with Ember

Downloads

3

Readme

ember-redux-data

Build Status

Blueprints and utilities for using the redux data stack in Ember.js

WIP! Work in Progress!

Redux Data Stack

Unlike Ember.js which recommends ember-data as your app's go-to data-consistency and remote-io layer (and react which recommends graphQL via relay), redux is lot less opinionated regarding what tools your app should use in this regard.

The purpose of this repo is to expose the tools and usage patterns that I personally found to cleanly and simply solve the problem of front-end data management. The tools used are:

  1. redux-actions - for FSA compliance
  2. redux-orm - for normalization and data consistency
  3. normalizr - for transforming and untransforming server-side responses

Concepts

Redux is big on functional programming, and, a such, a good data layer for use with redux should expose functions as pure as possible.

Remote APIs

Your app should have a requests/* directory that describes all the external endpoints your app will be hitting. requests should all be functions that return a promise with the external response:

run :: (any) -> Promise

For example: app/requests/user.js might look like:

import ajax from 'ember-ajax/request';

export function find(id) {
  return ajax(`my/endpoint/users/${id}`);
}

In general, keep your request functions as simple and stupid as possible. They shouldn't know about your application at all and so should theoretically be drag-and-droppable into any application.

Thunkers

What is a thunker? A thunker is a function that takes an remote response and transforms them into a redux-dispatchable thunk that will populate the redux store

type Thunk = (dispatch: Dispatch): Promise

type Thunker = (response: JSON): Thunk

Think of such a thunk as a batch of redux-actions.

To follow the convention set aside by redux's normalizr library, all thunkers should have the following form:

app/thunkers/example.js

export function toEntities(serverResponse) {
  // Do what you need to wrangle the server response
}
export default function exampleThunker(serverResponse) {
  return thunkifyEntities(toEntities(serverResponse));
}

normalizr normalizes data the following format:

  • Input:
{
  "id": "123",
  "author": {
    "id": "1",
    "name": "Paul"
  },
  "title": "My awesome blog post",
  "comments": [
    {
      "id": "324",
      "commenter": {
        "id": "2",
        "name": "Nicole"
      }
    }
  ]
}
  • Output:
{
  result: "123",
  entities: {
    "articles": {
      "123": {
        id: "123",
        author: "1",
        title: "My awesome blog post",
        comments: [ "324" ]
      }
    },
    "users": {
      "1": { "id": "1", "name": "Paul" },
      "2": { "id": "2", "name": "Nicole" }
    },
    "comments": {
      "324": { id: "324", "commenter": "2" }
    }
  }
}

Read about the normalizr here https://github.com/paularmstrong/normalizr

Selectors

What is a selector? Selectors are a function that take in the entire redux application state, filters out what is irrelevant for our use case, and returns only what we need. This is best illustrated with an example:

import { createSelector } from 'redux-orm';
const selectRetiredAuthors = createSelector(orm, (session) => session.Author.get({ isRetired: true }) );

Dispatchables

As per exisiting Ember convention, Ember.Route's model hook is where you should perform your remote calls and populate your redux store.

app/routes/user

import { findUser } from 'dummy/requests/user';
import toThunk from 'dummy/thunkers/user';

function model(dispatch, params) {
  return findUser(params.id).then(toThunk).then(dispatch);
}
...

How you string together your remote-api request into redux is up to your application. Although this example uses redux-thunk, if you need to use redux-saga, bare actions, or whatever, simply switch out the middle toThunk to whatever it is that creates an dispatchable object.

Accessing Data

Ember redux presents 2 similar ways of accessing redux state data:

Via delegates

And as with all redux apps, you pull data out of the redux store with designated data-delegate components like so:

{{#data-delegate-single-user userId=3 as |user|}}
  {{whatever-user-presentation-component user=user}}
{{/data-delegate-single-user}}

where your components/data-delegate-single-user.js would look like:

import connect from 'ember-redux/components/connect';
import Ember from 'ember';
import { find } from 'dummy/orm-selectors/users';

function states(reduxState, attrs) {
  const selectUser = find(attrs.userId);
  const user = selectUser(reduxState);
  return { user };  
}

function actions(dispatch) {
  return {
    something() {
      ...
    }
  };
}
export default connect(states, actions)(Ember.Component.extend({
  tagName: ''
}));

Via route-connect

If you wish to skip writing a data-delegate component for each new route, it's also possible to use https://github.com/dustinfarris/ember-redux-route-connect

  • Note: as of Feburary 15, 2017, there is a bug in ember-redux-route-connect where if you're using ember-redux 2.x.x, you'll run in to an npm:redux missing bug. You can fix this by using my fork here:

https://github.com/foxnewsnetwork/ember-redux-route-connect

import { findUser } from 'dummy/requests/user';
import toThunk from 'dummy/thunkers/user';
import route from 'ember-redux/route';
import connect from 'ember-redux-route-connect';

function model(dispatch, params) {
  return findUser(params.id).then(toThunk).then(dispatch);
}
function statesToCompute(state, params) {
  return {
    model: selectUserById(state, params.id)
  };
}
const Route = route({ model })(Ember.Route.extend({}));
export default connect(statesToCompute)(Route);

Boilerplate Checklist

In order to setup ember-redux-data for the first time, you must do the following:

  • [ ] add the orm reducer into your project app/reducers/index
import orm from 'dummy/orm';
import updater from 'ember-redux-data/updaters/model';
import { createReducer } from 'redux-orm';
import otherReducers from '...';

export default {
  orm: createReducer(orm, updater),
  ...otherReducers
}
  • [ ] update your app/orm.js with your models:
import { ORM } from 'redux-orm';
import Dress from './orm-models/dress';
import Performance from './orm-models/performance';
import Song from './orm-models/song';
import Vocaloid from './orm-models/vocaloid';

const orm = new ORM();
orm.register(Dress, Performance, Song, Vocaloid);

export default orm;

Cookbook Recipes

Installation

  • git clone <repository-url> this repository
  • cd ember-redux-data
  • npm install
  • bower install

Running

Running Tests

  • npm test (Runs ember try:each to test your addon against multiple Ember versions)
  • ember test
  • ember test --server

Building

  • ember build

For more information on using ember-cli, visit https://ember-cli.com/.