Closed PlanetIrata closed 7 years ago
I think the problem is not in the Freezer. You can use debounce function if you want to wait when user stopped text typing. And only after that try to trigger reaction which saved you state.
Hi,
This is like a freezer code cata, and here it is my solution.
http://jsbin.com/vecozewuko/1/edit?js,output
It's sure that you will need to store the values of your divs separately. I have used an array for those values, and a simple index to know what's the selected div.
When input values are stored in freezer directly, the live mode of freezer is needed since the user can type more than one character in the same tick and that would make your app lost those characters.
var store = new Freezer({...}, {live: true});
Keep in mind that it is a simple example, you might want to use reactions in order to keep your code organized properly.
Thank's kwoon and arqex for your answers, I'll give the live
option a try arqex, but I have another problem with Freezer/React, that you may help me to solve : in your jsbin sample above, you store the currently selected Div
as an array index in the store. It's ok for the demonstration, but how would you keep a trace of the selected Div
with a much more complex structure like a tree of deeply nested Div
components ? Suppose that we have Div
in Div
in Div
, and that any of them should be selectable (and show it is selected with an outline like in your sample), and have its text editable in the same unique <input>
field.
A possible solution would be to give each Div
in the tree a guid, then I could store the selected Div
guid in the store instead of an index, but I don't find this solution very elegant : firstly because I'd have to generate all those guid, and secondly because I'd have to pass 2 props to every Div
in the tree : the selected
property calculated by it's parent/container like in your sample, but also the guid of the selected Div
in order for each Div
to calculate the selected
property for its children...
It would take 2 lines of jQuery to do the same (remove the "selected" state from all the components of a tree, and add the "selected" state to one of them) and I can't figure out how to do that in React with an immutable store to manage the app state...all the samples I see about this are for a 1 level relationship between parent <> children (active button in a menu bar, active tab...).
Hope you could help, anyway, thank you again for your great work !
Hey @PlanetIrata
Sorry but I missed your last comment here completely!
What you are asking is the one of the most strongest point of freezer. Using freezer it's really easy to handle infinitely deep data, because you can update a node data using the methods given by the own node. See the JSON object editor:
http://jsbin.com/hugusi/1/edit?js,output
There, a React component is created for every node inside the JSON object. If you want to edit some part of it, you never care about how deep you are inside of the data tree, you just do something like
this.props.data.set({b:3});
That would re-render the whole editor with the new data, no need of generating guid or something similar.
Using react you need to stop thinking about how to change the UI to update the data (jQuery way), and start thinking the other way around. How can I change the data to update the UI?
For your "selected" problem you would probably need something like this in your freezer store:
var freezer = new Freezer({
data: {object1: {}, object2:{})
});
freezer.get().set({selected: freezer.get().data.object1});
You are storing what is the selected node separately, then in your component:
var className = 'component';
if( this.props.data === freezer.get().selected )
className += ' selected';
That would select your component, and deselect any other.
I hope that helped, even if the reply was really late.
Cheers
Here you have the explanation for the JSON editor: http://arqex.com/991/json-editor-react-immutable-data
Thanks arqex, but in your sample, what happens if the selected node is modified from elsewhere :
// Your sample
var freezer = new Freezer({
data: {object1: {}, object2:{})
});
freezer.get().set({selected: freezer.get().data.object1});
// Suppose now that somewhere in the code, object1 is modified
// (then its node is recreated)
freezer.get().data.object1.set({color: 'red'});
// From here, does freezer.get().selected is always a valid reference
// on the new muted object1 node, or a bad reference to the old node ?
// If freezer.get().selected is invalid it would mean that editing the selected object
// would "unselect it" immediately
Thanks
Freezer is clever enough to update all the references to the same object inside the store, so freezer.get().selected
will also be updated. freezer.get().selected === freezer.get().data.object1
.
@arqex Hi, your last comment, is that really true? I try this:
setTimeout(() => {
let state = this.props.store.get();
state.app.human.set(0, {firstName: 'Bernd'});
state.app.dog.set(99, {name: 'Brutus'});
setTimeout(() => {
let state = this.props.store.get();
state.app.human.set(0, Object.assign({}, {lastName: 'Wessels', dog: state.app.dog[99]}, state.app.human[0]));
setTimeout(() => {
let state = this.props.store.get();
state.app.dog.set(99, Object.assign({}, {age: 88}, state.app.dog[99]));
}, 1000);
}, 1000);
}, 1000);
}
but at the end
state.app.human[0]
is only {"lastName":"Wessels","dog":{"name":"Brutus"},"firstName":"Bernd"}
even though
state.app.dog[99]
is {"age":88,"name":"Brutus"}
Basically what I am asking is - how can I make sure that object references are preserved / distributed in freezer?
Freezer is made to preserve references: http://jsbin.com/nahejorufo/1/edit?js,console
Hi, here is my problem, suppose that I have 3 simple React
<div>
components containing a simple text and one React<input>
component to edit the<div>
texts (the<input>
is NOT a child of any<div>
, it's a separate component in a sidebar). When clicking on a<div>
, it has to become the "active component" : I have to put its current text in the<input>
and then, when the<input>
content is modified, set back in real time the content to this currently selected<div>
: each time a letter is typed in the<input>
, I do a set(...) to update the text of the<div>
in the store, then the component tree is re-rendered and the<div>
displays the new text.I've successfully manage this by using a "currSelectedDiv" property in my app state, but the problem is that this node is muted on every letter typed in the
<input>
, so I can't optimize the rendering with ShouldComponentUpdate, all the 3<div>
are re-rendered on each letter typed.I can't find a solution to resolve this. If the
<input>
was a child of each<div>
it would be easy, but how to manage a relation between 2 components that have no relationship without re-rendering all the components of the tree ?Hope you can help, thanks.