Skip to content

Commit

Permalink
Merge pull request #1 from iMrDJAi/v2
Browse files Browse the repository at this point in the history
v2.0.0
  • Loading branch information
iMrDJAi authored May 9, 2022
2 parents 53e7ce3 + e267b95 commit 4611cce
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 46 deletions.
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
21 changes: 21 additions & 0 deletions .github/workflows/npm-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Publish to NPM

on:
release:
types: [created]

jobs:
publish-npm:
runs-on: ubuntu-latest
steps:
- name: Clone repo
uses: actions/checkout@v2
- name: Setup .npmrc file
uses: actions/setup-node@v2
with:
node-version: '12.x'
registry-url: 'https://registry.npmjs.org'
- name: Publish!
run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
dist/
.DS_Store
117 changes: 91 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
***
# **useSync** - Custom React Hook
# **useSync**
[![npm](https://img.shields.io/npm/v/usesync?color=red)](https://www.npmjs.com/package/usesync)

A custom React hook to synchronize and share public state across different components on your React project.
A subscription based state management solution for React!
***

## Table of Contents
Expand All @@ -13,24 +13,24 @@ A custom React hook to synchronize and share public state across different compo

## Installation:

Install the hook from **npm**:
Install the package from **npm**:
```bash
$ npm install usesync --save
```

Then simply require it:
```js
const { useSync, sync, storage } = require("usesync")
const { useSync, sync, storage } = require("usesync") // CJS
```
or
```js
import useSync, { sync, storage } from "usesync"
import useSync, { sync, storage } from "usesync" // ESM
```

## Usage:
### useSync(id: string)
### useSync(id: string, initialValue?: any): any

This is the hook that you will use across your React components, the function registers them under a specific ID you will give:
This is the hook that you will use across your React components, it allows them to subscribe to a specific sync with the ID you give:
```js
const Component = () => {
useSync('hello')
Expand All @@ -42,49 +42,61 @@ const Component = () => {
}
```

To synchronize multiple components simply call the hook inside them and give the same ID:
Subscribing to muiltiple syncs is possible, just call the hook multiple times with different IDs:
```js
const ComponentA = () => {
useSync('hello')
const Component = () => {
useSync('id num 1')
useSync('id num 2')
return (
<div>
Hello World! (A)
Hello World!
</div>
)
}
const ComponentB = () => {
useSync('hello')
```

Updating sync IDs at runtime is allowed:
```js
const GreetUser = (id) => {
const user = getUser(id)
useSync(`Users ${id}`)
return (
<div>
Hello World! (B)
Hello {user.firstName}!
</div>
)
}
```

You can use the hook on a component for multiple times with multiple IDs:
To synchronize state in multiple components simply call the hook inside all of them and give the same ID:
```js
const Component = () => {
useSync('id num 1')
useSync('id num 2')
const ComponentA = () => {
const name = useSync('hello', 'World')
return (
<div>
Hello World!
Hello {name}! (A)
</div>
)
}
const ComponentB = () => {
const name = useSync('hello', 'World')
return (
<div>
Hello {name}! (B)
</div>
)
}
```

**Note:** it is possible to dynamically update a hook ID on a component with no issue.

### sync(id: string)
### sync(id: string, newValue?: any): void

The hook alone does nothing, to synchronize components registered under a specific ID you need to call this function, it causes to re-render all of them, here is an example:
The hook alone does nothing, to dispatch a sync you need to call this function, this will cause all the subscribed components to re-render. Here is an example:
```js
import React from 'react'
import ReactDOM from 'react-dom'
import useSync, { sync } from "usesync"


const ComponentA = () => {
useSync('Components')
return (
Expand Down Expand Up @@ -133,14 +145,67 @@ ReactDOM.render(<App />, document.getElementById('app'))
```
Try it on [CodePen](https://codepen.io/imrdjai/pen/zYKQzqw)!

### storage: object
**New:** You may pass a sync value to this function, and access it from the subscribed components:
```js
import React from 'react'
import ReactDOM from 'react-dom'
import useSync, { sync } from "usesync"


const initialValue = Math.random()

const ComponentA = () => {
const randomNumber = useSync('Components', initialValue)
return (
<div>
Random Number (A): {randomNumber}
</div>
)
}
const ComponentB = () => {
const randomNumber = useSync('Components', initialValue)
return (
<div>
Random Number (B): {randomNumber}
</div>
)
}
const ComponentC = () => {
const randomNumber = useSync('Components', initialValue)
return (
<div>
Random Number (C): {randomNumber}
</div>
)
}
const App = () => {
const handleClick = () => {
sync('Components', Math.random())
}
return (
<div>
<ComponentA />
<ComponentB />
<ComponentC />
<ComponentC />
<button onClick={handleClick}>re-render all</button>
</div>
)
}

ReactDOM.render(<App />, document.getElementById('app'))
```
Try it on [CodePen](https://codepen.io/imrdjai/pen/WNMwvJx)!

This is just an extra object publicly available across your app can be used to store data, you can put states for your componenets there, here is an example:
### storage: Object

This is an optional object that is globaly available across your app, it can be used to store states for your componenets. Here is an example:
```js
import React from 'react'
import ReactDOM from 'react-dom'
import useSync, { sync, storage } from "usesync"


storage.randomNumber = Math.random()

const ComponentA = () => {
Expand Down Expand Up @@ -199,4 +264,4 @@ Give this cool project a star ⭐! I will appreciate it ❤
[![GitHub Repo stars](https://img.shields.io/github/stars/iMrDJAi/useSync?style=social)](https://github.com/iMrDJAi/useSync)

## License
[MIT](https://github.com/iMrDJAi/useSync/blob/master/LICENSE) © [iMrDJAi](https://github.com/iMrDJAi)
[MIT](https://github.com/iMrDJAi/useSync/blob/master/LICENSE) © [iMrDJAi](https://github.com/iMrDJAi)
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{
"name": "usesync",
"version": "1.1.0",
"description": "A custom React hook to synchronize and share public state across different components on your React project",
"version": "2.0.0",
"description": "A subscription based state management solution for React!",
"main": "src/useSync.js",
"type": "module",
"repository": {
"type": "git",
"url": "git+https://github.com/iMrDJAi/useSync.git"
Expand Down
22 changes: 22 additions & 0 deletions src/useSync.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* A hook used within React components to subscribe to a specific sync with the given ID,
* and to access the sync value
* @param id The sync ID to subscribe to
* @param initialValue An initial value returned by the hook when the sync value is not available
* @returns The sync value
*/
declare function useSync (id: string, initialValue?: any): any
/**
* A function can be used everywhere to dispatch a sync with the given ID,
* and to pass a new sync value to the subscribed components
* @param id The sync ID to synchronize
* @param newValue A new sync value to pass
*/
declare function sync (id: string, newValue?: any): void
/**
* An optional object to store states inside
*/
declare const storage: { [key: string]: any }

export { useSync, sync, storage }
export default useSync
48 changes: 30 additions & 18 deletions src/useSync.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,40 @@
import { useReducer, useEffect } from 'react'
import { useReducer, useEffect, useRef } from 'react'

var syncs = {}

var useSync = id => {
var [, render] = useReducer(p => !p, false)
const syncs = {}

useEffect(() => {
if (!syncs[id]) syncs[id] = []
syncs[id].push(render)
const useSync = (id, initialValue) => {
const [, dispatch] = useReducer(state => !state, false)
const value = useRef(initialValue)
const render = (newValue) => {
value.current = newValue
dispatch()
}

return () => {
var index = syncs[id].findIndex(e => e === render)
syncs[id].splice(index, 1)
if (syncs[id].length === 0) delete syncs[id]
}
}, [id])
useEffect(() => {
if (!syncs[id]) syncs[id] = []
syncs[id].push(render)

return () => {
const index = syncs[id].findIndex(r => r === render)
syncs[id].splice(index, 1)
if (syncs[id].length === 0) delete syncs[id]
}
}, [id])

return value.current
}

var sync = id => {
if (syncs[id]) for (let render of syncs[id]) setTimeout(() => render(), 0)
const sync = (...args) => {
const [id, newValue] = args

if (!syncs[id]) return
for (const render of syncs[id]) {
setTimeout(() => args.length < 2 ? render() : render(newValue), 0)
}
}

var storage = {}
const storage = {}

export { useSync, sync, storage }

export default useSync
export default useSync

0 comments on commit 4611cce

Please sign in to comment.