radonjs / radon Goto Github PK
View Code? Open in Web Editor NEWObject oriented state management solution for front-end development.
Home Page: http://radonjs.org
License: MIT License
Object oriented state management solution for front-end development.
Home Page: http://radonjs.org
License: MIT License
Describe the bug
Getting the State on a Container Node with nested state containing an array, or object returns an array or object of VirtualNodes, rather than the formatted object. Rather, it should return an array of the primitive values only, not VirutalNodes
To Reproduce
Steps to reproduce the behavior:
Expected behavior
If I initialize state with an array, [1, 2]
the array returned when calling get state should consist of [1, 2]
rather than the current returned value of [VirtualNode {val: 1 ...}, VirtualNode {val: 2 ...}]
. This should be true of all values in VirtualNodes that are not ContainerNodes.
Test Snippet
test('State Is Correctly Initialized', () => {
let rootNode = new constructorNode('Root');
rootNode.initializeState({
testString: 'Testing',
testNum: 123,
testArr: ['1', '2', '3'],
testObject: {
key1: '1',
key2: '2',
key3: '3'
}
});
let generatedTree = combineNodes(rootNode);
expect(generatedTree.Root.getState().testString.val).toBe('Testing');
expect(generatedTree.Root.getState().testNum.val).toBe(123);
console.warn('State Is Correctly Initialized: Removed Due to Bug #56 - https://github.com/radonjs/Radon/issues/56');
//Removed Due to Bug #56 - https://github.com/radonjs/Radon/issues/56
//expect(generatedTree.Root.getState().testArr).toEqual(['1', '2', '3']);
//expect(generatedTree.Root.getState().testObject).toEqual({key1: '1', key2: '2', key3: '3'});
});
Hi, amazing work in here, it looks really promising.
Just one small thing though, the documentation on the Readme is too verbose and it is, imho, missing an example of Component that uses a piece of state from a silo.
You can see how to trigger a mutation, but not how to pass that piece of state to the component, let's say the equivalent of connect()
on Redux.
Is typescript definitions something that could be accepted as a PR into this be repository?
The React Bindings for Radon allow for the State tree to be bound to the Component tree, passing down the necessary props to each component in React. This is contrary to other state libraries which require the developer to manually pull in the require props from the state.
Binding the silo to components in React is achieved by wrapping the exported, or called class in a bind function which will perform the work or matching the component tree to the tree structure of the silo. These bound components will have props exposed to them matching the nodes in the silo.
import React from 'react';
import {bind} from 'react-radon';
class App extends React.Component {
/* React Code */
}
export default bind(App);
Binding components automatically makes a subscriber bond between the silo and the component. Allowing individual components to re-render when their watched node has a modifier run on it. This relationship allows for re-rendering the smallest amount of components, without the need for deep-diffing optimizing the speed of Radon's silo.
The Silo is modified through modifiers on the props that are attached to the components. Each prop assigned to the component has it's own set of modifiers passed down to it from the store. These modifiers act to update the piece of state that the component is tied to and are useful in reducing the scope of the re-render.
class App extends React.Component {
render() {
this.props.pieceOfSilo.modifierName(payload);
return /* element to render */
}
}
export default bind(App);
Describe the bug
Methods that update the state owned by a parent, don't actually trigger the parent to be re-render. Meaning that if the parent owns any primitive data types, they won't cause re-rendering when the are updated.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
The parent should auto subscribe to primitive data type changes, without forcing the developer to manually subscribe to the changes.
When Radon gets part of the silo to pass down to render functions, it can only return chunks of the state as its stored inside Radon, as a tree of silo Nodes. This means that when the developer gets the data back, it's in a format that is unrecognizable when compared to the data that they originally put into the silo with initializeState(). For this reason, Radon should also internally maintain something called a Virtual Silo.
The virtual silo is the developer-facing representation of the silo. While Radon needs to maintain two-way bindings in the silo (upward to parents and downward to children) the developer should only be able to access the state attached to a given node or its parents, which is why the virtual silo is a bottom-up tree.
The virtual silo will be tied to the Radon silo. Anytime a modifier changes parts of the silo, those changes will be represented in the virtual silo before they are sent to silo Node subscribers.
If a state node is initialized like so:
StateNode.initializeState({
lyric: "its the eye of the tiger its the thrill of the fight"
})
//A new node is initialized in the state, with the name "lyric" and the value
set to the string "its the eye of the tiger its the thrill of the fight"
StateNode.initializeModifiers({
lyric: {
append: (payload, previous, updateTo) => {
updateTo(previous + payload);
}
}
})
//A modifier is attached to lyric called "append" which takes a new string,
//then updates the value to the old string with the new string appended to the end
silo.subscribe(render, 'lyric')
function render(data){
//without a virtual silo, the lyric node would come into this function like so:
data.val; //"its the eye of the tiger its the thrill of the fight"
data.modifiers.append(", rising up to the challenge of our rivals")
//With a virtual silo, the data isn't wrapped like a silo node when it is pushed into render functions
data.val; //"its the eye of the tiger its the thrill of the fight"
data.append(", rising up to the challenge of our rivals")
}
//Using a virtual silo would make development using Radon more intuitive and useful to the developer.
//Because the data comes in a recognizable format, they can interface with it as they would an object.
The Silo is used to store the state of the App. It is structured to be bound to the Component structure of the Application being implemented. This approach allows the Silo to maintain encapsulation of the data that it hold while still providing access to the data in a predictable way. The Silo is a collection of SiloNodes, each with their own set of subscribers and modifiers which act to update elements of the Silo in a predictable way.
A SiloNode is a structured element of the Silo. The structure of the Node allows for updates that propagate to all of the dependent subscribers, along with allowing the minimum amount of subscribers to be notified for each change.
SiloNode {
value: {
//ChildSiloNodes
},
modifiers: {
modifier: //Code to Update Value
},
queue: [/* List of Modifiers To Be Implemented on Value*/],
subscribers: [/* List of Components Subscribed to Node Updates */],
parent: //ParentSiloNode
}
Modifiers act as the way to create predictable changes to the Silo in Radon. A modifier acts to perform some functionality before updating the value of a SiloNode and propagate the change to the Node's subscribers.
function modifierName (current, payload) {
return current + payload; //Changes the Node Value and Notifies Subscribers
}
SiloNodes that own a set of predictable Objects, which all may need similar modifiers can implement a special modifier which acts on individual children that it controls. This modifier takes an extra parameter, a key which tells the modifier which child it should run the modifier on.
function modifierName (current, key, payload) {
/* currentValue is the Value of the Child Selected with the Key Parameter. */
return current + payload; //Changes the Child Node Value and Notifies the Child's Subscribers
}
The Silo is structured into a tree as a means of providing encapsulation to state management. This tree structure binds to the Component Tree in order to pass props to each element that requires them. This connection between the State Tree and the Component Tree means that each Component will only get access to its parent's state, and the state that it holds, while being prevented from accessing the state of its sibling components.
The Async Queue is the way that Radon handles asynchronous changes to the Silo. When a modifier is run on a SiloNode that requires an asynchronous event, they are added to a queue. If another modifier seeks to update the SiloNode before the asynchronous change has updated the value and propagated the change, it will be added to the queue behind the asynchronous function. This allow SiloNode changes to happen asynchronously in a predictable manner.
Describe the bug
When creating modifiers with Radon, each modifier should be pulled out and placed into a the modifiers object of the parent, in the same structure as the data in the parent object. As the data in the parent should be deconstructed and back as it's primitive form.
To Reproduce
Steps to reproduce the behavior:
generatedTree
and set it to CombineNodes with the ConstructorNodegeneratedTree.Root.modifiers
and notice that it isn't filled with the created modifiers.Expected behavior
The data returned to the developer should be deconstructed from SiloNodes, meaning that it should have a .val
that has to be called, along with the modifier should be pulled out and kept in the ContainerNode, as the developer is expecting to work with a state that mirror's the way they setup the state tree.
Test Snippet
test('Collections Should Be Given KeySubscribe', () => {
let rootNode = new ConstructorNode('Root');
rootNode.initializeState({
testArr: [1, 2, 3],
testObj: {key1: 1, key2: 2, key3: 3}
});
let generatedTree = combineNodes(rootNode);
console.warn('Collections Should Be Given KeySubscribe: Removed Due to Bug Bug #57 - https://github.com/radonjs/Radon/issues/57');
//Removed Due to Bug Bug #57 - https://github.com/radonjs/Radon/issues/57
// expect(generatedTree.Root.modifiers.testArr.keySubscribe).toBeTruthy();
// expect(generatedTree.Root.modifiers.testObj.keySubscribe).toBeTruthy();
});
The getState method should return the variables and modifiers available to a component which will include parent data.
The notifySubs() method should inform the subscribers that the data it is watching has been changed. All the subscribers are the render functions of the components that are subscribing to data. Whenever the data changes, (whenever a modifier is called) notifySubs() is called, and the components are all rerendered.
Currently any modifier attached to an object parent in the silo is only capable of being called on the children of the parent. An option needs to be created to allow modifiers to be called on the object itself. We currently have the following syntax for adding object modifiers:
AppState.initializeModifiers({
object: {
changeValueInObject: (current, index, payload) => {
// returns a change to a value in an object
}
}
})
However, an object parent must also be able to accept the following modifier:
AppState.initializeModifiers({
object: {
changeObject: (current, payload) => {
// returns a change to the entire object
}
}
})
The combineNodes function must know to tell the difference between modifiers.
Currently the silo deconstructs objects and creates nodes for every primitive value. The silo must be able to create new nodes at runtime if a value is added to an object.
Describe the bug
Trying to modify an array with a modifier doesn't work as the current value that is passed into the array is an object, and not an array.
siloNode.initializedModifiers({
arrayNode: {
addToArray(current) {
current.push('test'); //Doesn't Work Because Current is An Object.
}
}
}
To Reproduce
Steps to reproduce the behavior:
Expected behavior
The current value passed into the modifier of the array function should be an array, rather than an object. As this is confusing to the developer who would be expecting an array to come in.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.