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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@bangcao2020/reactsync

v1.0.6

Published

Component to component data synchronization library for React applications.

Downloads

725

Readme

Author: Bang Cao.

linkedin.com/in/bangcao24

Lisense: MIT

Why ReactSync?

Managing state and data synchronization in React can be messy:

  • Context often causes unnecessary re-renders.
  • Global stores require boilerplate setup.
  • Prop drilling or ad-hoc event buses get complicated at scale.

ReactSync solves this:

  • Only the components that need updates re-render.
  • Automatic lifecycle handling — mount, unmount, sync.
  • Declarative component wiring with zero boilerplate.

Demos

  • https://github.com/bangcaodinh2020-droid/Miniblog-ReactSync
  • https://github.com/bangcaodinh2020-droid/ECommercialApp-ReactSync
  • https://github.com/bangcaodinh2020-droid/Demo-TableComponent-With-ReactSync

Features

  • Plug & Play: Just two components needed: and your child components.
  • Targeted Updates: Only components subscribed to a key update.
  • Declarative Sync: Components declare which state they sync with.
  • Lifecycle Safe: Auto-registration and cleanup on mount/unmount.
  • High DX: Zero-store, no boilerplate, no manual subscriptions.
  • Performance Ready: Designed for 1,000+ components with minimal overhead.

Advanced Usage / API

  • Add multiple components dynamically — auto-registration handled.
  • Remove components — auto cleanup, no orphan subscriptions.
  • Access App data from any child component directly.

Performance

  • Tested with 5,000+ components
  • Targeted updates prevent broadcast re-renders
  • Minimal memory overhead
  • Works smoothly even with dynamic mount/unmount cycles

Installation

npm install @bangcao2020/reactsync

or

yarn add @bangcao2020/reactsync

////////////////

## 💡 Quick Start

///////////////
Example 1:
///////////////
We can use this ReactSync without the central store.

import {BaseApp, Test3} from "@bangcao2020/reactsync";

export function App() {

  return (

    <div>

     <Test3 channel={"count"} defaultValue={5}> A </Test3>
     <Test3 channel={"count"} defaultValue={60}> B </Test3>
   
   </div>

  )
}

Then at another place, we use the app as below.
<App/>

////////////////
Example 2:
////////////////
We can use this ReactSync without the central store.

import {BaseApp, Test4} from "@bangcao2020/reactsync";

export function App() {

  return (

    <div>

     <Test4 > C </Test4>
     <Test4 > D </Test4>

   </div>

  )
}

Then at another place, we use the app as below.
<App/>


///////////////
Example 3:
///////////////
We can use this ReactSync without the central store.

import {BaseApp, Test4} from "@bangcao2020/reactsync";

export function App() {

  return (

    <div>
     <Test3 channel={"count"} defaultValue={5}> A </Test3>
     <Test3 channel={"count"} defaultValue={60}> B </Test3>
     <Test4 > C </Test4>
     <Test4 > D </Test4>

   </div>

  )
}

Then at another place, we use the app as below.
<App/>


///////////////
Example 4:
///////////////
OR we can use an app as central store.
export  class TestApp extends BaseApp {

  render(){
  return (

   <div>

    <Test3 channel={"count"} defaultValue={5}> A </Test3>
    <Test3 channel={"count"} defaultValue={60}> B </Test3>
     <Test4 > C </Test4>
     <Test4 > D </Test4>
     <Test5 id='E' data={{syncers:["F"]}}> E</Test5>
     <Test5 id='F' data={{syncers:["E"]}}> F</Test5>
     <Test6 id='k' data={{syncers:["l"]}}> K</Test6>
     <Test6 id='l' data={{syncers:["k"]}}> L</Test6>

   </div>

  );
}


}

Then at another place ( main, or index), we use the app as below.

<TestApp id="testApp" data={{syncData:{count:10}}}></TestApp>
- syncData, play a role as store.
<TestApp id="testApp" data={{syncData:{count:10, tableData:{}}}}></TestApp>
- or empty store
<TestApp id="testApp" data={{syncData:{}}}></TestApp>
///////////////////////
Example 5:
///////////////////////

<BaseApp id="baseApp" data={{syncData:{count:10}}}>
     <Test3 channel={"count"} defaultValue={5}> A </Test3>
      <Test3 channel={"count"} defaultValue={60}> B </Test3>
     <Test4 > C </Test4>
     <Test4 > D </Test4>
     <Test5 id='E' data={{syncers:["F"]}}> E</Test5>
     <Test5 id='F' data={{syncers:["E"]}}> F</Test5>
     <Test6 id='k' data={{syncers:["l"]}}> K</Test6>
     <Test6 id='l' data={{syncers:["k"]}}> L</Test6>
</BaseApp>


///////////////////////////////////////////////////
 Example 6: Customize your component with useChannel
///////////////////////////////////////////////////

import {useChannel} from "@bangcao2020/reactsync";
export const CustomComponent = (props: any) => {
  const [count, setCount] = useChannel(props.channel, props.defaultValue, props);

  const onClick = () => {
    setCount(count + 1);
  };

  return (
    <div onClick={onClick}>
      Click Me {props.children} ({count})
    </div>
  );
};

then use it
 <CustomComponent channel={"countChannel"} defaultValue={5}> A </CustomComponent>
 <CustomComponent channel={"countChannel"} defaultValue={50}> B </CustomComponent>

///////////////////////
Example 6: Or like this.
///////////////////////
export const AnotherComponent = (props: any) => {
  const [xyz, setXyz] = useChannel("abc", 3, props);

  const onClick = () => {
    setXyz(xyz + 1);
  };

  return (
    <div onClick={onClick}>
      Click Me {props.children} ({xyz})
    </div>
  );
};

Then use it
<AnotherComponent> A</AnotherComponent>
<AnotherComponent> B</AnotherComponent>
///////////////////////////////////////
If you want to use Id and central store.
Example 8:
////////////////////////////////////////
import type {BaseProps} from "@bangcao2020/reactsync";

export const ComponentA=(props: BaseProps)=>
{
  const syncer = useRef(null);
  const [count, setCount] = useState(0);
  useEffect(()=>{

          if (syncer.current) return;
          syncer.current = new Syncer(props);
          syncer.current.onNotified = onNotified;

  }, []);
  const onClick=()=>{
        //send message, data to another component
        syncer.current.sendMessage("Hello", {count: count+1});
        setCount(count + 1);
  }
  const onNotified = (event: any)=>{
        //Get message, data from other components
        setCount(event.data.count);
  }

  return (<div onClick={onClick}>
          Click Me {props.children} ({count})
  </div>);
}
Then you can use it.
<BaseApp id="baseApp" data={{syncData:{count:10}}}/>
<ComponentA id='E' data={{syncers:["F"]}}> E</ComponentA>
<ComponentA id='F' data={{syncers:["E"]}}> F</ComponentA>
///////////////////////////////////
Example 9: you can use getSyncer
//////////////////////////////////
export const ComponentB=(props: BaseProps)=>
{
  const onNotified = (event: any)=>{
        // where you get the update, message from other components
        setCount(event.data.count);
  }
  const syncer = useRef(null);

  const [count, setCount] = useState(0);
  
  const onClick=()=>{
        //call sendMessage anytime you need to send data to another components
        //
        if(syncer.current)
        syncer.current.sendMessage("Hello", {count: count+1});
        setCount(count + 1);
  }

  useEffect(()=>{

          if (syncer.current) return;
          syncer.current = getSyncer(props, onNotified);


  }, []);


  return (<div onClick={onClick}>
          Click Me {props.children} ({count})
  </div>);
}

Then you use it somewhere else.
<BaseApp id="baseApp" data={{syncData:{count:10}}}/>
<ComponentB id='l' data={{syncers:["k"]}}> L</ComponentB>
<ComponentB id='k' data={{syncers:["l"]}}> L</ComponentB>

////////////////////////////////////////////////////
Example 10: work with table.
///////////////////////////////////////////////////

import { App, TableComponent } from "@bangcao2020/reactsync";

function Dashboard() {
  return (
    <App data={{ syncData: { tableData: "initial value" } }}>
      <TableComponent
        id="table1"
        data={{ tableName: "tableData", syncers: ["view1", "view2"] }}
      >
        My Table
      </TableComponent>
    </App>
  );
}

Explanation:

id → Unique identifier for the component

tableName → Key in App’s syncData

syncers → Other components to notify when data changes

⚡ Advanced Usage
import { App, TableComponent } from "@bangcao2020/reactsync";

function Dashboard() {
  return (
    <App data={{ syncData: { tableData: [], userData: {} } }}>
      <TableComponent
        id="tableA"
        data={{ tableName: "tableData", syncers: ["tableB", "tableC"] }}
      >
        Table A
      </TableComponent>

      <TableComponent
        id="tableB"
        data={{ tableName: "tableData", syncers: ["tableA"] }}
      >
        Table B
      </TableComponent>

      <TableComponent
        id="tableC"
        data={{ tableName: "userData", syncers: ["tableA"] }}
      >
        Table C
      </TableComponent>
    </App>
  );
}



Example:

import BaseComponent, {ButtonComponent,
  MessageType,
  TestComponent,
  TableComponent,
  CounterComponent,
  ViewRowComponent,
  PaginationComponent
} from "@bangcao2020/reactsync";


---

## 📊 Usage

### Example 1- View, delete a row.


<App id="appLayout" data={{ syncData:{
mode:"production",
tableData:{rows:AddRow(10), columns: columns},
table2:{rows: rows2, columns: columns2},

                      }}}/>

### Then you can use like this.

<ViewRowComponent id="viewRow1"
data={{fromTableName:"tableData",
          fields:["Col 1", "Col 2", "Col 3"],
          styles:{}
          }}>View 1</ViewRowComponent>

          <TableComponent id="testTable"
          data={{tableName:"tableData",
          tableTarget:"table2",
          actions:[{label:"Delete", type:"deleteARow"}, {label:"View", type:"viewARow"},],
          syncers:["viewRow1", "viewRow2", "testTable2"],

          }}> My Table</TableComponent>

---

### Example 2 - Customize table, pagination

---

<TableComponent id="testTable11"
data={{tableName:"tableData",
                  tableTarget:"table2",
                  syncers:["viewRow11", "viewRow12", "testTable12"],
                  actions:[{label:"Delete", type:"deleteARow"}, {label:"View", type:"viewARow"}],
                  styles:{table:"table table-info table-hover", tbody:"", tr:"", th:"bg-primary", td:"", button:"rounded bg-primary border border-0 mx-1"  },
                  }}> My Table</TableComponent>

                   <PaginationComponent id={"pagination11"}
                   data={{rowsPerPage:10,
                    numOfPageNode:4,
                    tableName:"tableData",
                    syncers:["testTable11"],
                    styles:{button:"page-link text-info"}}}></PaginationComponent>



### Example 3 - Move data between tables

<TableComponent id="testTable11"
data={{tableName:"tableData",
                  tableTarget:"table2",
                  syncers:["viewRow11", "viewRow12", "testTable12"],
                  actions:[{label:"Delete", type:"deleteARow"}, {label:"View", type:"viewARow"}],
                  styles:{table:"table table-info table-hover", tbody:"", tr:"", th:"bg-primary", td:"", button:"rounded bg-primary border border-0 mx-1"  },
                  }}> My Table</TableComponent>

                   <PaginationComponent id={"pagination11"}
                   data={{rowsPerPage:10,
                    numOfPageNode:4,
                    tableName:"tableData",
                    syncers:["testTable11"],
                    styles:{button:"page-link text-info"}}}></PaginationComponent>



### Example 4 - Edit row data


<EditRowComponent id="viewRow32"
data={{
styles:{button:"bg-success rounded"},

             }}>View Edit</EditRowComponent>


          <TableComponent id="testTable31"
          data={{tableName:"tableData",
          tableTarget:"table2",
          syncers:["viewRow31", "viewRow32", "testTable32"],
          actions:actions,
          styles:styles,
          }}> My Table</TableComponent>