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

warped-components

v0.3.0

Published

An opinionated way to build frontend applications

Downloads

9

Readme

Warped Components

Build Status Greenkeeper Enabled

An opinionated way to build frontend applications. Works nicely with Warped Reducers.

Installation

Warped Components requires React 16.8.3 or later

$ npm install --save warped-components react xstream

In a nutshell

  • The view is handled by React.
  • The state is handled by Redux.
  • The effects are handled by Cycle with XStream.
  • The wiring is handled by Warped Components.

Warped Components does two things to facilitate your application:

  1. It manages the creation of your Redux store, and uses React Redux to connect your components to the global state. But instead of taking mapStateToProps and mapDispatchToProps functions, it takes a selectors object whose values are functions that map the state to individual properties, and an actions object whose values are functions that given a payload, return a Redux Standard Action.
  2. It lets you associate your Cycle applications and Redux reducers with specific React components. Then, whenever React renders those components, Warped Components will update the global Redux reducer to contain only the reducers found in the tree, and it will shut down and start up the appropriate Cycle applications based on which are present in the tree. All of this is achieved by using React Collect.

This approach has the following benefits:

  1. An architectural benefit, where all the logic related to a component, including asynchronous side-effects and state transformations, are all kept in a single place. This means that most changes to the application will be centred around a single directory in your source code.
  2. If you use code-splitting and multiple entry points, this approach facilitates a smaller main bundle, because the reducers and effects for components outside of the initial render tree don't have to be included.
  3. Your Redux reducers and Cycle applications are "hot by design". This means that if you use module.hot, your reducer logic and side-effect logic is also automatically hot-reloaded (given that you don't remount the WarpedApp, but only its children).

API

Automatic wiring

warped :: WarpedOptions -⁠> ReactComponent -⁠> ReactComponent

Does zero to two distinct things to a component, depending on the options:

  • Connects it to the state using the given selectors and actions.
  • Associates a Redux reducer and a Cycle application with the component.

The options (all optional, though at least one should be provided) are:

  • selectors: An object whose keys correspond to properties, and values are functions that receive the state and return the value for the property.
  • actions: A hash-map of action creators. The underlying component will receive them as props, and when called, the resulting action is dispatched to the store.
  • reducer: A Redux reducer - a function which takes a state and an action, and returns a new state. Warped Components makes sure that whenever the connected component is mounted, this reducer will act as part of the reducers of your store.
  • effects: A Cycle application - a function which takes a mapping of stream / stream-producers, and returns a mapping of streams.

If you would just like the reducer or effects to be mounted without a "view", for example when a reducer is in change of handling some state shared between multiple components, then pass null as the ReactComponent. The returned ReactComponent can still be rendered anywhere in the tree to have its reducer and/or effects be mounted.

For the definition of actions and reducer, we recommend using Warped Reducers, and for the definition of the selectors, we highly recommend using an Optics library like Ramda's lens related functions or partial.lenses.

import {warped} from 'warped-components';
import {createReducer, noopAction} from 'warped-reducers';
import {lensProp, compose, set, view} from 'ramda';
import React from 'react';

// We use a lens to describe our slice of the global state.
// How you do it is up to you, though.
export const dataState = compose (
  lensProp ('app'),
  lensProp ('data')
);

// We use warped-reducers to create our reducer and actions.
export const {types, actions, reducer} = createReducer ('App') ({
  loadData: noopAction,
  setData: set (dataState)
});

// A small Cycle app describes the side-effects of our component.
export const effects = ({action, http}) => ({
  http: action.filter (({type}) => type === types.loadData).mapTo ({
    url: 'https://api.github.com/users/Avaq',
    category: types.loadData
  }),
  action: http.select (types.loadData).flatten ().map (({body: {name}}) =>
    actions.setData (name)
  )
});

// The selectors are used to map the global state to component props.
export const selectors = {
  data: view (dataState)
};

// This is our view.
export const App = ({data, loadData}) => (
  <div>
    <h1>{data || 'name unknown'}</h1>
    <button onClick={loadData}>Load!</button>
  </div>
);

// Warped Components wires the view to all of the above.
export default warped ({reducer, effects, selectors, actions}) (App);

WarpedApp :: ReactComponent

This component does the wiring for your application:

  • Setting up your Redux store, and swapping out its reducer as needed.
  • Setting up your Cycle application, and swapping out its main as needed.
  • Linking the Redux Store and Cycle apps by adding two drivers:
    1. state: A read-only driver exposing a memory stream of the latest Redux state.
    2. action: A read-write driver exposing a stream of dispatched actions and allowing other actions to be dispatched.

It takes the following optional props:

  • initialState: Some initial state for your store.
  • enhancer: Store enhancer, allows middleware, debug tooling, etcetera.
  • drivers: Cycle drivers determine what kind of effects can occur.
import {WarpedApp} from 'warped-components';
import {devToolsEnhancer} from 'redux-devtools-extension';
import {makeHTTPDriver} from '@cycle/http';
import {render} from 'react-dom';
import React from 'react';
import App from './my-app';

const drivers = {http: makeHTTPDriver ()};

render (
  <WarpedApp enhancer={devToolsEnhancer ()} drivers={drivers}>
    <App />
  </WarpedApp>,
  document.getElementById ('app')
);

Redux Utilities

If you prefer using React Redux and Redux directly, rather than using the WarpedApp, you can use these utilities to ease the interaction with Warped Reducers.

compileSelectors :: StrMap ((a, b) -⁠> c) -⁠> (a, b) -⁠> StrMap c

Given a mapping of selectors, returns a mapStateToProps function, as accepted by connect from React Redux.

The selectors are given the state (and previous props), and are expected to return a slice of the state. We recommend using Optics, such as the lens-related functions from Ramda, to create the selectors.

compileDispatchers :: StrMap (a -⁠> b) -⁠> (b -⁠> c) -⁠> StrMap (a -⁠> c)

Given a mapping of action creators, as returned from createReducer, returns a mapDispatchToProps function, as accepted by connect from React Redux.

combineReducers :: Array ((a, b) -⁠> a) -⁠> (a, b) -⁠> a

Given an array of reducers, returns a single reducer which transforms the state by calling all reducers in sequence.

Cycle utilities

combineCycles :: Array (StrMap Any -⁠> StrMap Stream) -⁠> StrMap Any -⁠> StrMap Stream

Given an array of main functions that take sources and return sinks, returns a single main function which combines the effects of each.