Skip to content

Commit f871dc6

Browse files
committed
initial commit
1 parent 3d8ec5f commit f871dc6

File tree

8 files changed

+337
-1
lines changed

8 files changed

+337
-1
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

README.md

+64-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,64 @@
1-
# react-global-store
1+
# react-global-store
2+
3+
I need a name for my new React store.
4+
5+
Why I created it? Because I very like Redux, but:
6+
7+
- It lot of code. (Action builders, reducers, Selectors, Connectors...)
8+
- It hard to refactor.
9+
- It hard to get IDE autocomplete.
10+
11+
I have created a new store, that it's usefull for small team (or team of 1 developer) in Agile environment
12+
who would like to develop faster, and still keep the app run fast.
13+
14+
- You get one store and can access to all of it in any component.
15+
- You can update any part of the store directly from every component.
16+
- No need to create action builders or selectors. The store is a simple read/write JavaScript JSON object.
17+
- You can create all your components memoized, and setup to render them only when specific field changed in the store.
18+
- It run fast.
19+
- You get auto-complete to all fields in your store automatically.
20+
- No bugs of changing array or object values without cloning. You can change them in-place.
21+
22+
Demo:
23+
24+
```js
25+
// First you should creating the store.
26+
// Usually you will create one store for each app and share this variable.
27+
// Usually you will put this in separate file.
28+
const GlobalStore = require('react-global-store2')
29+
30+
const store = GlobalStore.NewStore({
31+
key1:0,
32+
key2:0,
33+
// You can add many keys as you wish
34+
// It can be functions, arrays, or Whatever you want.
35+
})
36+
37+
38+
39+
function App(){
40+
// This component will automatically re-render when store.key1 will change.
41+
store.useRerenderIfChange(()=>[store.key1])
42+
function incrementKey1(){
43+
store.key1++
44+
store.updateStore() // This will check which component should re-render since the last update.
45+
}
46+
return <div onClick={incrementKey1}>
47+
Store key1: {store.key1}
48+
<ChildComponent />
49+
</div>
50+
}
51+
52+
function ChildComponent() {
53+
// This component will automatically re-render when store.key2 or store.key1 will change.
54+
store.useRerenderIfChange(()=>[store.key2,store.key1])
55+
function incrementKey2(){
56+
store.key2++
57+
store.updateStore()
58+
}
59+
return <div onClick={incrementKey2}>
60+
Store key1: {store.key1}
61+
Store key2: {store.key2}
62+
</div>
63+
}
64+
```

demo/index.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React from 'react'
2+
const store = require('./store')
3+
function App(){
4+
store.useRerenderIfChange(()=>[store.key1])
5+
function incrementKey1(){
6+
store.key1++
7+
store.updateStore()
8+
}
9+
return <div onClick={incrementKey1}>
10+
Store key1: {store.key1}
11+
<ChildComponent />
12+
</div>
13+
}
14+
15+
function ChildComponent() {
16+
store.useRerenderIfChange(()=>[store.key2])
17+
function incrementKey2(){
18+
store.key2++
19+
store.updateStore()
20+
}
21+
return <div onClick={incrementKey2}>
22+
Store key2: {store.key2}
23+
</div>
24+
}

demo/store.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
var store = require('../index')
2+
3+
module.exports=store.NewStore({
4+
key1:0,
5+
key2:0
6+
})
7+

index.js

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
"use strict";
2+
var __assign = (this && this.__assign) || function () {
3+
__assign = Object.assign || function(t) {
4+
for (var s, i = 1, n = arguments.length; i < n; i++) {
5+
s = arguments[i];
6+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7+
t[p] = s[p];
8+
}
9+
return t;
10+
};
11+
return __assign.apply(this, arguments);
12+
};
13+
exports.__esModule = true;
14+
exports.NewStore = void 0;
15+
//@ts-check
16+
var react_1 = require("react");
17+
var lodash_isequal_1 = require("lodash.isequal");
18+
var lodash_clonedeep_1 = require("lodash.clonedeep");
19+
function NewStore(state, persistentProvider) {
20+
//@ts-ignore
21+
var Store = state;
22+
var prevPersistented = __assign({}, ((Store === null || Store === void 0 ? void 0 : Store.persistent) || {}));
23+
var callbacks = {};
24+
var callbacksNextAvailableKey = 0;
25+
function updateStoreNow() {
26+
scheduled = false;
27+
for (var i in callbacks) {
28+
callbacks[i]();
29+
}
30+
if (Store.persistent) {
31+
if (!persistentProvider) {
32+
throw new Error('cannot use persistent without persistent provider');
33+
}
34+
for (var _i = 0, _a = Object.keys(Store.persistent); _i < _a.length; _i++) {
35+
var key = _a[_i];
36+
var val = Store.persistent[key];
37+
// console.log({key,val:JSON.stringify(val),prev:prevPersistented[key]})
38+
if (JSON.stringify(val) != prevPersistented[key]) {
39+
persistentProvider.setKey(key, val);
40+
prevPersistented[key] = JSON.stringify(val);
41+
// console.log({prevPersistented})
42+
}
43+
}
44+
}
45+
}
46+
var scheduled = false;
47+
function Schedule() {
48+
if (scheduled)
49+
return;
50+
scheduled = true;
51+
setTimeout(updateStoreNow, 0);
52+
}
53+
/**
54+
* @example useRerenderIfChange((store) => [store.scale, store.othervalue])
55+
* @param callback {(store:Store)=>void}
56+
*/
57+
Store.useRerenderIfChange = function (callback) {
58+
var _a = react_1.useState(0), _ = _a[0], setMeToRerender = _a[1];
59+
var callbacksKeyRef = react_1.useRef(callbacksNextAvailableKey++);
60+
/** The array from the user. Cloned so new changes will not be there */
61+
var lastValueRef = react_1.useRef(lodash_clonedeep_1["default"](callback(Store)));
62+
react_1.useEffect(function () {
63+
// When object mount, add a function to the callbacks, to change if the value changes
64+
// it will trigged by the "updateStore below"
65+
callbacks[callbacksKeyRef.current] = function () {
66+
var currentValue = callback(Store); // The new array of values calculated from the store
67+
if (!lodash_isequal_1["default"](currentValue, lastValueRef.current)) {
68+
lastValueRef.current = lodash_clonedeep_1["default"](currentValue); // Update the old array.
69+
setMeToRerender(function (prev) { return prev + 1; }); // Rerender the objects
70+
}
71+
};
72+
return function () {
73+
// When object unmount we don't need this callback any more.
74+
delete callbacks[callbacksKeyRef.current];
75+
};
76+
}, []);
77+
return lastValueRef.current;
78+
};
79+
Store.updateStore = function () {
80+
Schedule();
81+
};
82+
return Store;
83+
}
84+
exports.NewStore = NewStore;

index.ts

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//@ts-check
2+
import { useState, useEffect, useRef } from "react"
3+
import isEqual from "lodash.isequal"
4+
import cloneDeep from "lodash.clonedeep"
5+
6+
interface a{
7+
updateStore:()=>void
8+
useRerenderIfChange:(callback)=>void
9+
persistent:{[key:string]:any}
10+
isReady?:Promise<void>
11+
}
12+
interface PersistentProvider {
13+
setKey:(key:string,value:any)=>Promise<void>
14+
getKey:(key:string)=>Promise<any>
15+
}
16+
export function NewStore<T>(state:(T & {persistent:{[key:string]:any}}),persistentProvider?:PersistentProvider):(a & T) {
17+
//@ts-ignore
18+
var Store:(a & T)=state
19+
var prevPersistented = {... (Store?.persistent || {})}
20+
var callbacks = {}
21+
var callbacksNextAvailableKey = 0
22+
23+
function updateStoreNow() {
24+
scheduled=false
25+
for (var i in callbacks) {
26+
callbacks[i]()
27+
}
28+
if(Store.persistent) {
29+
if(!persistentProvider) {
30+
throw new Error('cannot use persistent without persistent provider')
31+
}
32+
for(let key of Object.keys(Store.persistent)) {
33+
var val=Store.persistent[key]
34+
// console.log({key,val:JSON.stringify(val),prev:prevPersistented[key]})
35+
36+
if(JSON.stringify(val)!=prevPersistented[key]) {
37+
persistentProvider.setKey(key,val)
38+
prevPersistented[key]=JSON.stringify(val)
39+
// console.log({prevPersistented})
40+
}
41+
}
42+
}
43+
}
44+
var scheduled=false
45+
function Schedule(){
46+
if(scheduled) return
47+
scheduled=true
48+
setTimeout(updateStoreNow,0)
49+
}
50+
/**
51+
* @example useRerenderIfChange((store) => [store.scale, store.othervalue])
52+
* @param callback {(store:Store)=>void}
53+
*/
54+
Store.useRerenderIfChange=function(callback) {
55+
56+
var [_, setMeToRerender] = useState(0)
57+
var callbacksKeyRef = useRef(callbacksNextAvailableKey++)
58+
59+
/** The array from the user. Cloned so new changes will not be there */
60+
var lastValueRef = useRef(cloneDeep(callback(Store)))
61+
useEffect(() => {
62+
// When object mount, add a function to the callbacks, to change if the value changes
63+
// it will trigged by the "updateStore below"
64+
callbacks[callbacksKeyRef.current] = () => {
65+
var currentValue = callback(Store) // The new array of values calculated from the store
66+
if (!isEqual(currentValue, lastValueRef.current)) {
67+
lastValueRef.current = cloneDeep(currentValue) // Update the old array.
68+
setMeToRerender((prev) => prev + 1) // Rerender the objects
69+
}
70+
}
71+
return () => {
72+
// When object unmount we don't need this callback any more.
73+
delete callbacks[callbacksKeyRef.current]
74+
}
75+
}, [])
76+
return lastValueRef.current
77+
}
78+
79+
Store.updateStore=function() {
80+
Schedule()
81+
}
82+
return Store
83+
}
84+
85+

package-lock.json

+45
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "react-global-store2",
3+
"version": "1.0.2",
4+
"description": "",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/Aminadav/react-global-store.git"
12+
},
13+
"keywords": [
14+
"react"
15+
],
16+
"author": "Aminadav Glickshtein",
17+
"license": "ISC",
18+
"bugs": {
19+
"url": "https://github.com/Aminadav/react-global-store/issues"
20+
},
21+
"homepage": "https://github.com/Aminadav/react-global-store#readme",
22+
"dependencies": {
23+
"lodash.clonedeep": "^4.5.0",
24+
"lodash.isequal": "^4.5.0",
25+
"react": "^17.0.1"
26+
}
27+
}

0 commit comments

Comments
 (0)