Comparing version 0.6.0-alpha.0 to 0.6.0-alpha.1
@@ -60,9 +60,10 @@ "use strict"; | ||
// | ||
const expr = reactive_box_1.default.expr; | ||
const box = reactive_box_1.default.box; | ||
const sel = reactive_box_1.default.sel; | ||
const flow = reactive_box_1.default.flow; | ||
const rb = reactive_box_1.default; | ||
const expr = rb.expr; | ||
const box = rb.box; | ||
const sel = rb.sel; | ||
const flow = rb.flow; | ||
const internal_flow_stop = flow.stop; | ||
const internal_untrack = reactive_box_1.default.untrack; | ||
const internal_transaction = reactive_box_1.default.transaction; | ||
const internal_untrack = rb.untrack; | ||
const internal_transaction = rb.transaction; | ||
const un_expr = (a, b) => ((a = expr(a, b)), un(a[1]), a); | ||
@@ -69,0 +70,0 @@ const un_flow = (a, b, c) => ((a = flow(a, b, c)), un(a[2]), a); |
{ | ||
"name": "realar", | ||
"version": "0.6.0-alpha.0", | ||
"description": "React state manager", | ||
"version": "0.6.0-alpha.1", | ||
"description": "The advanced state manager less than 5kB for React", | ||
"repository": { | ||
@@ -88,3 +88,3 @@ "url": "https://github.com/betula/realar" | ||
}, | ||
"gitHead": "63f40b460fda901bafe4d774f20d0efceda2988e" | ||
"gitHead": "21ad5e66abb6481316cd8048ec15466c333ddd54" | ||
} |
416
README.md
@@ -5,151 +5,48 @@ # Realar | ||
Object oriented state manager for React based on [reactive mathematic](https://github.com/betula/reactive-box). | ||
State manager to reduce developers' coding time and increase the lifetime of your codebase. | ||
[Light](https://bundlephobia.com/result?p=realar), [Fast](https://github.com/betula/reactive-box-performance), and Pretty looked :kissing_heart: | ||
Realar targeted to all scale applications up to complex enterprise solutions on modular architecture. | ||
Realar targeted to clean code, modulable architecture, and time to delivery user experience. | ||
- __Logic free React components__. Perfect instruments for moving all component logic outside. Your React component will be pure from any unnecessary code, only view, only JSX, no more. | ||
Transparent functional reactive programming with classes, decorators and [babel jsx wrapper](https://github.com/betula/babel-plugin-realar) | ||
- __Lightweight and Fast__. Less then 5kB. Aims at the smallest size of the resulting bundle. And only parts are updated in which is really necessary to make changes. | ||
```javascript | ||
class Ticker { | ||
@prop count = 0 | ||
tick = () => ++this.count; | ||
} | ||
- __Value and Signal__ is the big elephants remind Store and Action from Redux. Allows you to perform familiar coding techniques, and also add many modern features. | ||
const ticker = new Ticker(); | ||
setInterval(ticker.tick, 200); | ||
- __Modular Architecture__. Possibilities for the implementation of three levels of logic availability. | ||
- Shared stateful logic pattern (known as "service") for decomposing applications logic to separate independent or one direction dependent modules with global accessibility. | ||
- Declaration one scope and use as many reactive values as you want without the need to define a new React context for each changeable value with context level accessibility. | ||
- And enjoy clean React components with local logic decomposition. | ||
const App = () => ( | ||
<p>{ticker.count}</p> | ||
) | ||
``` | ||
[Try wrapped version on CodeSandbox](https://codesandbox.io/s/realar-ticker-classes-c9819?file=/src/App.tsx) | ||
- __Decorators for clasess lovers__. Support OOP as one of the primary syntax. The implementation of transparent functional reactive programming (TFRP) with React (looks similar to Mobx). And the babel plugin for automatic wrap all arrow functions defined in the global scope with JSX inside to observe wrapper. | ||
Realar **targeted to** all scale applications up to complex enterprise solutions on micro apps architecture. | ||
You can use as many from Realar as you want. For small websites or theme switchers, two functions are enough:ok_hand: Step by step on applications scale stairs you can take more and more. From sharing state to all application parts, to modulable architecture with micro apps composition. | ||
- __Decorators for clasess lovers__. And babel plugin for automatic wrap all arrow functions defined in the global scope with JSX inside to observe wrapper for the total implementation of transparent functional reactive programming (TFRP) in javascript with React. | ||
- __Logic free React components__. Perfect instruments for moving all component logic to the class outside. Your React component will be pure from any unnecessary code, only view, only JSX, no more. | ||
- __Shared stateful logic decomposition__. The pattern for decomposing applications logic to separate independent or one direction dependent modules. Each module can have its own set of reactive values. (ssr, comfort “mock” mechanism for simple unit testing). Shared stateful logic is a single instantiated class with total accessibility from all parts of your application. In another terminology - services. | ||
- __Lightweight and Fast__. Really light ~3kB. And only those components are updated in which it is really necessary to make changes. | ||
- __React component context level scopes__. Declaration one scope and use as many reactive values as you want without the need to define a new React context for each changeable value. | ||
- __Signals__ are a necessary part of reactive communication, well knows for most javascript developers as actions or events. In Realar that possibility provides through signal abstraction. Possibility for subscribing to signal, call signal and wait for the next signal value everywhere on the codebase. And for a tasty, reading the last called value from a signal. | ||
### Usage | ||
It looks likes very clear and natively, and you can start development knows only two functions. | ||
The start piece of code with basic operations of reactive value and signals | ||
`prop`. Reactive value marker. Each reactive value has an immutable state. If the immutable state will update, all React components that depend on It will refresh. | ||
`shared`. One of the primary reasons for using state manager in your application is a shared state accessing, and using shared logic between scattered React components and any place of your code. | ||
```javascript | ||
import React from 'react'; | ||
import { prop, shared } from 'realar'; | ||
import { value } from 'realar' | ||
class Counter { | ||
@prop value = 0; | ||
// Realar's adventure will start from "value", | ||
// is an immutable reactive container such as | ||
// "store" from Redux terminology | ||
const store = value(0) | ||
inc = () => this.value += 1; | ||
dec = () => this.value -= 1; | ||
} | ||
// You can easily make functional update | ||
// signals similar to an "action" from Redux | ||
const inc = store.updater(state => state + 1) | ||
const add = store.updater((state, num: number) => state + num) | ||
const sharedCounter = () => shared(Counter); | ||
// Watch updating | ||
store.to((state) => console.log(state)) | ||
const Count = () => { | ||
const { value } = sharedCounter(); | ||
return <p>{value}</p>; | ||
}; | ||
const Buttons = () => { | ||
const { inc, dec } = sharedCounter(); | ||
return ( | ||
<> | ||
<button onClick={inc}>+</button> | ||
<button onClick={dec}>-</button> | ||
</> | ||
); | ||
}; | ||
const App = () => ( | ||
<> | ||
<Count /> | ||
<Buttons /> | ||
<Count /> | ||
<Buttons /> | ||
</> | ||
); | ||
export default App; | ||
// And run signals as usual functions | ||
inc() // console output: 1 | ||
add(10) // console output: 11 | ||
``` | ||
[Try on RunKit](https://runkit.com/betula/60b4e0cab769ca0021660348) | ||
For best possibilities use [realar babel plugin](https://github.com/betula/babel-plugin-realar), your code will be so beautiful to look like. | ||
But otherwise necessary to wrap all React function components that use reactive values inside to `observe` wrapper. [Try wrapped version on CodeSandbox](https://codesandbox.io/s/realar-counter-k9kmw?file=/src/App.tsx). | ||
### Access visibility levels | ||
The basic level of scopes for React developers is a **component level scope** (_for example `useState`, and other standard React hooks has that level_). | ||
Every React component instance has its own local state, which is saved every render for the component as long as the component is mounted. | ||
In the Realar ecosystem `useLocal` hook used to make components local state. | ||
```javascript | ||
class CounterLogic { | ||
@prop value = 0; | ||
inc = () => this.value += 1 | ||
} | ||
const Counter = () => { | ||
const { value, inc } = useLocal(CounterLogic); | ||
return ( | ||
<p>{value} <button onClick={inc}>+</button></p> | ||
); | ||
} | ||
export const App = () => ( | ||
<> | ||
<Counter /> | ||
<Counter /> | ||
</> | ||
); | ||
``` | ||
[Play wrapped on CodeSandbox](https://codesandbox.io/s/realar-component-level-scope-classes-m0i10?file=/src/App.tsx) | ||
This feature can be useful for removing logic from the body of a component to keep that free of unnecessary code, and therefore cleaner. | ||
**context component level scope** | ||
```javascript | ||
const Counter = () => { | ||
const { value, inc } = useScoped(CounterLogic); | ||
return ( | ||
<p>{value} <button onClick={inc}>+</button></p> | ||
); | ||
} | ||
export const App = () => ( | ||
<Scope> | ||
<Scope> | ||
<Counter /> | ||
<Counter /> | ||
</Scope> | ||
<Counter /> | ||
</Scope> | ||
); | ||
``` | ||
[Play wrapped on CodeSandbox](https://codesandbox.io/s/realar-context-component-level-scope-classes-wivjv?file=/src/App.tsx) | ||
### Signals | ||
@@ -183,3 +80,3 @@ | ||
```javascript | ||
const add = signal(); | ||
const add = signal<number>(); | ||
@@ -190,3 +87,3 @@ const store = value(1); | ||
add(15); | ||
console.log(store.val); // 16 | ||
console.log(store.val); // console output: 16 | ||
``` | ||
@@ -200,10 +97,9 @@ [Edit on RunKit](https://runkit.com/betula/6013af7649e8720019c9cf2a) | ||
const listen = async () => { | ||
(async () => { | ||
for (;;) { | ||
await fire; // await as a usual promise | ||
await fire.promise; // await as a usual promise | ||
console.log('Fire'); | ||
} | ||
} | ||
})(); | ||
listen(); | ||
setInterval(fire, 500); | ||
@@ -213,2 +109,4 @@ ``` | ||
### Core | ||
@@ -250,40 +148,57 @@ | ||
Realar provides big possibility abstractions for reactive flow. We already know about reactive value container, reactive expressions, and subscribe mechanism. But also have synchronization between data, cycled reactions, cached selectors, and transactions. | ||
Realar provides big possibility abstractions for reactive flow. We already know about reactive value container, reactive expressions, and subscribe mechanism. But also have synchronization between data, cycled reactions, cached selectors, transactions and etc. | ||
### Low level usage | ||
### OOP Usage | ||
Transparent functional reactive programming with classes, decorators and [babel jsx wrapper](https://github.com/betula/babel-plugin-realar) | ||
```javascript | ||
const count = value(0); | ||
class Ticker { | ||
@prop count = 0 | ||
tick = () => ++this.count; | ||
} | ||
const tick = () => count.val++; | ||
setInterval(tick, 200); | ||
const ticker = new Ticker(); | ||
setInterval(ticker.tick, 200); | ||
const App = () => { | ||
const value = useValue(count); | ||
return ( | ||
<p>{value}</p> | ||
) | ||
} | ||
const App = () => ( | ||
<p>{ticker.count}</p> | ||
) | ||
``` | ||
[Try on CodeSandbox](https://codesandbox.io/s/realar-ticker-functional-6s3mx?file=/src/App.tsx) | ||
[Try wrapped version on CodeSandbox](https://codesandbox.io/s/realar-ticker-classes-c9819?file=/src/App.tsx) | ||
It looks likes very clear and natively, and you can start development knows only two functions. | ||
`prop`. Reactive value marker. Each reactive value has an immutable state. If the immutable state will update, all React components that depend on It will refresh. | ||
`shared`. One of the primary reasons for using state manager in your application is a shared state accessing, and using shared logic between scattered React components and any place of your code. | ||
```javascript | ||
import React from "react"; | ||
import { value, useValue } from "realar"; | ||
import React from 'react'; | ||
import { prop, shared } from 'realar'; | ||
const [get, set] = value(0); | ||
class Counter { | ||
@prop value = 0; | ||
const next = () => get() + 1; | ||
inc = () => this.value += 1; | ||
dec = () => this.value -= 1; | ||
} | ||
const inc = () => set(next()); | ||
const dec = () => set(get() - 1); | ||
const sharedCounter = () => shared(Counter); | ||
const Current = () => { | ||
const value = useValue(get); | ||
return <p>current: {value}</p>; | ||
const Count = () => { | ||
const { value } = sharedCounter(); | ||
return <p>{value}</p>; | ||
}; | ||
const Next = () => { | ||
const value = useValue(next); | ||
return <p>next: {value}</p>; | ||
const Buttons = () => { | ||
const { inc, dec } = sharedCounter(); | ||
return ( | ||
<> | ||
<button onClick={inc}>+</button> | ||
<button onClick={dec}>-</button> | ||
</> | ||
); | ||
}; | ||
@@ -293,7 +208,6 @@ | ||
<> | ||
<Current /> | ||
<Next /> | ||
<button onClick={inc}>+</button> | ||
<button onClick={dec}>-</button> | ||
<Count /> | ||
<Buttons /> | ||
<Count /> | ||
<Buttons /> | ||
</> | ||
@@ -304,137 +218,78 @@ ); | ||
``` | ||
[Try on CodeSandbox](https://codesandbox.io/s/realar-pure-counter-1ue4h?file=/src/App.tsx). | ||
### API | ||
For best possibilities use [babel jsx wrapper](https://github.com/betula/babel-plugin-realar), your code will be so beautiful to look like. | ||
**value** | ||
But otherwise necessary to wrap all React function components that use reactive values inside to `observe` wrapper. [Try wrapped version on CodeSandbox](https://codesandbox.io/s/realar-counter-k9kmw?file=/src/App.tsx). | ||
The first abstraction of Realar is reactive container - `value`. | ||
The `value` is a place where your store some data as an immutable struct. | ||
When you change value (rewrite to a new immutable struct) all who depend on It will be updated synchronously. | ||
#### React component access visibility level | ||
For create new value we need `value` function from `realar`, and initial value that will store in reactive container. | ||
The call of `value` function returns array of two functions. | ||
- The first is value getter. | ||
- The second one is necessary for save new value to reactive container. | ||
The basic level of scopes for React developers is a component level scope (_for example `useState`, and other standard React hooks has that level_). | ||
```javascript | ||
const [get, set] = value(0); | ||
Every React component instance has its own local state, which is saved every render for the component as long as the component is mounted. | ||
set(get() + 1); | ||
In the Realar ecosystem `useLocal` hook used to make components local stateful logic. | ||
console.log(get()); // 1 | ||
``` | ||
[Edit on RunKit](https://runkit.com/betula/6013af7649e8720019c9cf2a) | ||
In that example | ||
- for a first we created `value` container for number with initial zero; | ||
- After that, we got the value, and set to its value plus one; | ||
- Let's print the result to the developer console, that will is one. | ||
We learned how to create a value, set, and get it. | ||
**on** | ||
The next basic abstraction is expression. | ||
Expression is a function that read reactive boxes or selectors. It can return value and write reactive values inside. | ||
We can subscribe to change any reactive expression using `on` function _(which also works with signal)_. | ||
```javascript | ||
const [get, set] = value(0); | ||
class CounterLogic { | ||
@prop value = 0; | ||
inc = () => this.value += 1 | ||
} | ||
const next = () => get() + 1; | ||
const Counter = () => { | ||
const { value, inc } = useLocal(CounterLogic); | ||
on(next, (val, prev) => console.log(val, prev)); | ||
return ( | ||
<p>{value} <button onClick={inc}>+</button></p> | ||
); | ||
} | ||
set(5); // We will see 6 and 1 in developer console output, It are new and previous value | ||
export const App = () => ( | ||
<> | ||
<Counter /> | ||
<Counter /> | ||
</> | ||
); | ||
``` | ||
[Edit on RunKit](https://runkit.com/betula/6013ea214e0cf9001ac18e71) | ||
[Play wrapped on CodeSandbox](https://codesandbox.io/s/realar-component-level-scope-classes-m0i10?file=/src/App.tsx) | ||
In that example expression is `next` function, because It get value and return that plus one. | ||
This feature can be useful for removing logic from the body of a component to keep that free of unnecessary code, and therefore cleaner. | ||
**selector** | ||
#### React context access visibility level | ||
Necessary for making high-cost calculations and cache them for many times of accessing without changing source dependencies. And for downgrade (selection from) your hierarchical store. | ||
```javascript | ||
const store = value({ | ||
address: { | ||
city: 'NY' | ||
} | ||
}); | ||
const Counter = () => { | ||
const { value, inc } = useScoped(CounterLogic); | ||
const address = selector(() => store.val.address); | ||
return ( | ||
<p>{value} <button onClick={inc}>+</button></p> | ||
); | ||
} | ||
on(address, ({ city }) => console.log(city)); // Subscribe to address selector | ||
console.log(address.val.city); // Log current value of address selector | ||
store.update(state => ({ | ||
...state, | ||
user: {} | ||
})); | ||
// Store changed but non reaction from address selector | ||
store.update(state => ({ | ||
...state, | ||
address: { | ||
city: 'LA' | ||
} | ||
})); | ||
// We can see reaction on deleveloper console output with new address selector value | ||
export const App = () => ( | ||
<Scope> | ||
<Scope> | ||
<Counter /> | ||
<Counter /> | ||
</Scope> | ||
<Counter /> | ||
</Scope> | ||
); | ||
``` | ||
[Edit on RunKit](https://runkit.com/betula/60338ff8dbe368001a10be8c) | ||
**cache** | ||
[Play wrapped on CodeSandbox](https://codesandbox.io/s/realar-context-component-level-scope-classes-wivjv?file=/src/App.tsx) | ||
`cache` - is the decorator for define `selector` on class getter. | ||
```javascript | ||
class Todos { | ||
@prop items = []; | ||
@cache get completed() { | ||
return this.items.filter(item => item.completed); | ||
} | ||
} | ||
``` | ||
**cycle** | ||
```javascript | ||
const [get, set] = value(0); | ||
### API | ||
cycle(() => { | ||
console.log(get() + 1); | ||
}); | ||
- [value](./docs/api.md) | ||
- [selector](./docs/api.md) | ||
- [on](./docs/api.md) | ||
- [cache](./docs/api.md) | ||
- [cycle](./docs/api.md) | ||
- [sync](./docs/api.md) | ||
set(1); | ||
set(2); | ||
// In output of developer console will be 1, 2 and 3. | ||
``` | ||
[Edit on RunKit](https://runkit.com/betula/601a733c5bfc4e001a38def8) | ||
- Takes a function as reactive expression. | ||
- After each run: subscribe to all reactive values accessed while running | ||
- Re-run on data changes | ||
**sync** | ||
```javascript | ||
const [getSource, setSource] = value(0); | ||
const [getTarget, setTarget] = value(0); | ||
sync(getSource, setTarget); | ||
// same as sync(() => getSource(), val => setTarget(val)); | ||
setSource(10); | ||
console.log(getTarget()) // 10 | ||
``` | ||
[Edit on RunKit](https://runkit.com/betula/601a73b26adfe70020a0e229) | ||
_Documentation not ready yet for `effect`, `loop`, `pool`, `stoppable`, `initial`, `mock`, `unmock`, `free`, `transaction`, `untrack`, `isolate`, `ready`, `un` functions. It's coming soon._ | ||
### Demos | ||
@@ -446,2 +301,3 @@ | ||
### Articles | ||
@@ -461,21 +317,7 @@ | ||
And update your babel config for support class decorators and using [babel plugin](https://github.com/betula/babel-plugin-realar) for automatic observation arrow function components. | ||
- If you prefer classes with decorators [update your babel config for support](https://babeljs.io/docs/en/babel-plugin-proposal-decorators). | ||
- And configure [babel jsx wrapper](https://github.com/betula/babel-plugin-realar) for automatic observation arrow function components if you want to use it. | ||
```javascript | ||
//.babelrc | ||
{ | ||
"plugins": [ | ||
["@babel/plugin-proposal-decorators", { "legacy": true }], | ||
["@babel/plugin-proposal-class-properties", { "loose": true }], | ||
["realar", { | ||
"include": [ | ||
"src/components/*", | ||
"src/pages/*" | ||
] | ||
}] | ||
] | ||
} | ||
``` | ||
Enjoy and happy coding! | ||
import React, { Context, FC } from 'react'; | ||
import rb from 'reactive-box'; | ||
import rb_lib from 'reactive-box'; | ||
@@ -7,13 +7,11 @@ /* | ||
[] Make pre.0 version | ||
[] Add first example to documentation | ||
[] Add store.updater.multiple | ||
[] Complete the draft explanation of the introductory section | ||
[] Add second example to documentation | ||
``` | ||
// First example: | ||
const v = value(0); | ||
const inc = v.updater(v => v + 1); | ||
const add = v.updater((v, num: number) => v + num); | ||
// -- only react examples here -- | ||
// Second example | ||
@@ -31,3 +29,2 @@ const Loader = () => { | ||
[] maybe make val as readonly property for fix "never" type for prepended values and signals | ||
@@ -41,2 +38,3 @@ or I can make readonly val only for prepended values and signals (think about). | ||
Backlog: | ||
[] Try terser for result code size optimization | ||
[] .as.trigger | ||
@@ -502,2 +500,3 @@ [] .as.value.trigger | ||
const rb = rb_lib; | ||
const expr = rb.expr; | ||
@@ -504,0 +503,0 @@ const box = rb.box; |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
0
141322
2414
314