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

flux-condenser

v0.2.1

Published

**Condenser**: _Another term for capacitor._

Downloads

3

Readme

Flux Condenser

Condenser: Another term for capacitor.

This is a small lightweight but powerful, implementation of Facebook's Flux architecture.

Important Flux Condenser is not compatible with IE.

Why to make another Flux implementation?

This implementation differs, from other implementations of Flux, in a fundamental aspect: Subscriptions.

Stores are subscribed to the dispatcher to listen to actions separately. This means that only those callbacks subscribed to the dispatched action are executed, therefore the developer doesn't need to implement the huge switch to determine which action was called.

Also, whatever needs to subscribe to changes in a Store, it does through a subscription to an extractor function. Every time the store changes, it runs every extractor annotated to it, and for each extractor that changed from the previous execution, subscribers are notified of the change.

Parts

Dispatcher

The dispatcher is the main orchestrator of the architecture. Every action is sent through the dispatcher and the dispatcher will inform each listener registered to that action.

It is highly recommended to use a single dispatcher for the entire application, although nothing prevents the developer to create multiple dispatchers instances if it is required.

Global dispatcher

The global dispatcher is accessible from:

import { dispatcher } from 'flux-condenser';

or

const fluxCondenser = require('flux-condenser');
fluxCondenser.dispatcher;

Stores

Stores are where the data lives. They must subscribe to a dispatcher to process the actions sent to them.

createStore

There is a createStore helper function to easily create a store that is connected to the global dispatcher.

Usage
import { createStore } from 'flux-condenser';
// or
const { createStore } = require('flux-condenser');

const storeName = Symbol('store6');
const initialValue = { count: 0};

const condenser = function (state) {
  return {
    count: state.count + 1,
  };
};

const condensers = [
  ['ACCUMULATE', condenser],
];

const store = createStore(storeName, initialValue, condensers);

export store;
// or
module.exports.store = store;

Extractors

Extractors are functions that receive the state as a parameter and return a part of that state. For example:

function extractorExample(state) {
  return state.interestingProperty;
}

Adding an extractor to a store

A common use for the store is to listen to changes in the store's state. To do that, stores have a method subscribe that accepts a data handler and an extractor as arguments, for example:

store.subscribe(
  function dataHandler(data) {
    // Do something with your data
  },
  function extractor(state) {
    // Return part of your
  },
);

The dataHandler function will receive as an argument, whatever the extractor function returns.

Several dataHandler functions can be attached to a single extractor, so it is a good idea to share the extractor function to be reused wherever is needed, for example:

extractor.js

export function getMessageCounter(state) {
  state.counter;
}

header.js

import { getMessageCounter } from '/extractor.js';
import { store } from 'stores.js';

store.subscribe(function (counter) {
  document.title = '(' + counter + ') messages';
}, getMessageCounter);

messages.js

import { getMessageCounter } from '/extractor.js';
import { store } from 'stores.js';

store.subscribe(function (counter) {
  document.getElementById('messages-badge').textContent = counter;
}, getMessageCounter);

createExtractor

createExtractor is a helper function to create extractors that require extra parameters besides the state. There is also createMemoExtractor helper that provides a level of cache (memoization) returning the same function for the same input parameters.

Usage
import { createExtractor } from 'flux-condenser';
// or
const { createExtractor } = require('flux-condenser');

const getOptionForIdExtractor = createExtractor(function (state, id) {
  return state.options[id];
});

// store was created before
store.subscribe(function (option) {
  // Do something with the options.
}, getOptionForIdExtractor('id1'));

store.subscribe(function (option) {
  // Do something with the options.
}, getOptionForIdExtractor('id2'));

Execute extractors on demand

Stores can also execute extractors on demand. When that happens, the store will execute the given extractor against its state and return the extractor result.

Usage
import { createExtractor } from 'flux-condenser';
// or
const { createExtractor } = require('flux-condenser');

const getOptionForIdExtractor = createExtractor(function (state, id) {
  return state.options[id];
});

// store was created before
const option = store.execExtractor(getOptionForIdExtractor('id1'));

Actions

Actions are more like a concept rather than a function perse. Raising an action is just calling the dispatcher with an action name and a payload, to be spread to those stores that are subscribed to that action.

There are two ways to dispatch an action:

From a dispatcher

dispatcher.dispatch({ action: 'ACTION_NAME', payload: { property: value } });

From a store

// store was created before
store.dispatch({ action: 'ACTION_NAME', payload: { property: value } });

createActionDispatcher

createActionDispatcher is a helper function to create action dispatchers, which will dispatch actions on the global dispatcher.

Usage
import { createActionDispatcher } from 'flux-condenser';
// or
const { createActionDispatcher } = require('flux-condenser');

const action1Dispatcher = createActionDispatcher('ACTION_1', (property1, property2) => {
  return {
    property1,
    property2,
  };
});

// This will call the global dispatcher with an action object like {action: 'ACTION_1', payload: {property1: 'value1', property2: 'value2'}}
action1Dispatcher('value1', 'value2');

// This will call the global dispatcher with an action object like {action: 'ACTION_1', payload: {property1: 'value3', property2: 'value4'}}
action1Dispatcher('value3', 'value4');

Typescript

This project implements TypeScript definitions for the use in TypeScript projects.

Usage

/// <reference types="node" />

import { createStore, createExtractor } from 'flux-condenser';
const storeName = Symbol('my-store');

// actions
export enum Actions {
  SET_HEADER = 'SET_HEADER',
  SET_SUB_TITLE = 'SET_SUB_TITLE',
}

// Store data types
type Header = {
  title: string;
  subTitle: string;
};

type Body = {
  amount: number;
  children: Record<string, string>;
};

type Data = {
  header?: Header;
  body?: Body;
};

// condensers
function setHeader(initialState: Data, payload: Header): Data {
  return {
    ...initialState,
    header: payload,
  };
}

function setBody(initialState: Data, payload: Body): Data {
  return {
    ...initialState,
    body: payload,
  };
}

// Create a store
export const store = createStore<Data, Actions>(storeName, {}, [
  [Actions.SET_HEADER, setHeader],
  [Actions.SET_SUB_TITLE, setBody],
]);

// Extractors
const getBodyExtractor = (data: Data) => {
  return data.body;
};

// Extractors creators
const extractorFunction = (data: Data, id: string): string | undefined => {
  return data.body && data.body.children[id];
};
const extractor = createExtractor<Data, [string], string | undefined>(extractorFunction);

// Add extractors to store
store.subscribe((body: Body | undefined) => {
  // do something with the body
}, getBodyExtractor);

store.subscribe((value: string | undefined) => {
  // do something with the value
}, extractor('some id'));

Webpack with multiple bundles

Flux Condenser module should be included only once per application. In a multiple bundle Webpack solution, it means we need to extract the Flux Condenser module in a separate bundle that is going to be used by every other bundle. Webpack must be configured with the optimization runtimeChunk option to create a runtime chunk with common modules.

module.exports = {
  entry: {...},
  output: {...},
  module: {...},
  optimization: {
    runtimeChunk: 'single',
    ...
  },
};

Collaboration

I am working on the first fully implemented version of this library, once that is done, I will accept PRs.