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

bazar

v0.5.2

Published

State container

Downloads

71

Readme

Bazar

One-to-One and One-to-Many communications between Components.

Bazar is a 500b (framework agnostic) container of connections between js Components. It is designed with React in mind, so are the examples. However you can use Bazar with/without any JS framework of choice. It has been tested with success in connecting React and Vue components inside the same app.

Table of Contents

Installation

With NPM:

  npm install bazar

Without:

  <script src="https://unpkg.com/[email protected]/dist/bazar.js"></script>

Demo

  • Codepen demo showcasing onPoke: https://codepen.io/lucagez/full/GeRZeg

  • Lots of snippets below.

TL;DR

One-to-Many:

  1. Some components (a), (b) express an interest in a registered component (c).
  2. (c) updates its state and issue an edict.
  3. (a) and (b) immediately receive the updated (c)'s state.

One-to-One:

  1. A component (a) stores some info useful for the unreachable component (b).
  2. (a) can poke (b) passing the useful info.

Usage

Bazar provides One-to-One and One-to-Many communications between Components through a global store which contains all the required connections to do so. In order to accomplish that you have to:

  1. Register some components.
  2. Dispatch events (either via edict or poke).

Register a component

The id prop is the only strictly requirement to register a new component. However a component registered like that is useless as it cannot edict neither being poked.

import React, { Component } from 'react';
import { register } from 'bazar';

class C1 extends Component {
  constructor() {
    super();
    this.state = {};

    register({
      id: 'C1' // unique id
    });
  }

  render = () => <p>C1</p>
} 

Register a component: can edict

A component with the ability to issue an edict must have a method to sync its state. You can choose which part of the state you prefer to keep in sync.

import React, { Component } from 'react';
import { register, edict } from 'bazar';

class C1 extends Component {
  constructor() {
    super();
    this.state = {
      updated: false,
    };

    register({
      id: 'C1', // unique id
      sync: () => this.state, // function
    });
  }

  // Calling `edict` in `setState` callback will invoke `onEdict` of interested
  // components with the updated state of C1.
  onUpdate = () => this.setState({
    update: true,
  }, () => edict('C1'));

  render = () => <button onClick={this.onUpdate}>update</button>
} 

Register a component: can poke

A component with the ability to poke could also be stateless. As the poke function is anonymously invoked.

import React, { Component } from 'react';
import { poke } from 'bazar';

const C1 = () => (
  <button 
    onClick={() => poke('registeredComponent', { passed: 'argument' })}>
    update
  </button>
);

Register a component: can getState

A component with the ability to provide its current state must have a valid sync method.

import React, { Component } from 'react';
import { register } from 'bazar';

class C1 extends Component {
  constructor() {
    super();
    this.state = { state: 'to keep in sync' }

    register({
      id: 'C1',
      sync: () => this.state,
    });
  }
  render = () => <div>C1</div>
};

Register a component: willRerender

To make the presence of multiple components with the same id obvious, Bazar will throw an error when will find some duplicates. When a component rerender will automatically re-register itself in the global store. Pass willRerender: true when registering to notify Bazar that the current component will re-register itself.

import React, { Component } from 'react';
import { register } from 'bazar';

class C1 extends Component {
  constructor() {
    super();
    register({
      id: 'C1',
      willRerender: true,
    });
  }
  render = () => <div>C1</div>
};

One-to-Many communication

In the following example:

  1. Registration of 3 components: (a), (b), (c).
  2. (a), (b) express an interest in a registered component (c).
  3. (c) updates its state and issue an edict.
  4. (a) and (b) immediately receive the updated (c)'s state, via onEdict.

note: Usually this kind of communication is useful between STATEFUL components. As the onEdict function comes handy for updating a component's state.

import React, { Component } from 'react';
import { register, edict } from 'bazar';

class A extends Component {
  constructor() {
    super();
    register({
      id: 'A',
      interests: ['C'],
      // When C issues an `edict`, this `onEdict` function is invoked.
      // You can update A's state accordingly.
      onEdict: (id, state) => this.setState({ received: true }),
    });
  }
  render = () => <div>A</div>
};

class B extends Component {
  constructor() {
    super();
    this.state = { received: false };
    register({
      id: 'B',
      interests: ['C'],
      onEdict: (id, state) => console.log(`I just received a ${state} update from ${id}`),
    });
  }
  render = () => <div>B</div>
};


class C extends Component {
  constructor() {
    super();
    this.state = { interesting: false };
    register({
      id: 'C',
      sync: () => this.state,
    });
  }

  // Issuing an `edict` on setState callBack => so we have access to the just updated state.
  clicked = () => this.setState({ interesting: true }, edict('C'));

  render = () => <div onClick={this.clicked}>C</div>
};

One-to-One communication

In the following example:

  1. Registration of 2 (unrelated) components: (a), (b).
  2. A component (a) stores some info useful for the unreachable component (b).
  3. (a) can poke (b) passing the useful info.

note: This kind of communication is useful between a STATELESS component and a STATEFUL one. The poke function is completely anonimous, so it can be invoked from an unregistered component.

import React, { Component } from 'react';
import { register, poke } from 'bazar';

const A = (props) => <button onCLick={() => poke('B', props)}>A</button>

class B extends Component {
  constructor() {
    super();
    this.state = { empty: {} };
    register({
      id: 'B',
      onPoke: (arg) => this.setState({ empty: arg }),
    });
  }
  render = () => <div>B</div>
};

Get (registered) component's state

Invoking getState you can get the current state of the component belonging to the provided id. If the component is not registered undefined will be returned.

import React, { Component } from 'react';
import { register, getState } from 'bazar';

const A = (props) => <button onCLick={() => getState('B')}>A</button>

class B extends Component {
  constructor() {
    super();
    this.state = { empty: {} };
    register({
      id: 'B',
      sync: () => this.state,
    });
  }
  render = () => <div>B</div>
};

Clearing store

You can clear bazar store at any time. Useful if connecting many components that will be repeated many times.

e.g. You are connecting widgets of a dashboard. Every widget has an id relative to the dashboard. You render one dashboard at a time but using the same widgets. Clearing the store between dashboard renders prevents ID clashes and let's you reuse the same IDs within the dashboard.

import React, { Component } from 'react';
import { clearStore } from 'bazar';

// Call it without arguments.
clearStore();

API

register

Most important part of Bazar as it stores all the required informations to connect all the registered components.

| param | type | required | default | explaination | |-----------|----------|----------|-----------|----------------------------------------------------------------| | id | string | yes | | unique identifier for the registered Component | | sync | function | no | undefined | sync state on request | | interests | array | no | [] | express interests on Components | | onEdict | function | no | undefined | invoked when a Component in interests issue an edict | | onPoke | function | no | undefined | invoked when poke is called providing id as first argument |

  • onEdict: invoked passing (id, state) as arguments.
  • onPoke: invoked passing (arg) an optional argument.

edict

Issuing an edict from a stateful Component.

| param | type | required | default | explaination | |-------|--------|----------|---------|--------------------------------------------------------| | id | string | yes | | Identifier of the component that is issuing an edict |

getState

Safely get the current state from a registered component

| param | type | required | default | explaination | |-------|--------|----------|---------|----------------------------------------------------------------| | id | string | yes | | Returns undefined if no Component or no sync method is found |

poke

Poking Component passing optional argument.

| param | type | required | default | explaination | |-------|--------------|----------|-----------|----------------------------------------------------------| | id | string | yes | | Throw Error if the id component has no onPoke method | | arg | user-defined | no | undefined | Optional argument to pass to onPoke |

clearStore

clearStore will empty the bazar store. It's called without specifying arguments.

Contributing

Every PR is welcomed 🎉 If you have ideas on how to improve upon this library don't hesitate to email me at [email protected].

License

MIT.