For me, I can't use the 'snapshot app-db and discard' as the app-db is synchronised with the server periodically. As you mention, I have a number of roots in my app, one for 'ui' entries and one for 'views' which are populated by the server, even if I want to discard the 'ui' root I really don't want to discard the 'views'.
I avoid local state as well simply because the benefit of being able to capture the whole app-db and attach it to a bug report is awesome. On 15 May 2015 at 15:31, Daniel Kersten <[email protected]> wrote: > Am I correct that what you want is a temporary "scratchpad" where you make > edits which can then be committed to the global state, or discarded, based > on user action? > > There are two ways that I've used to do this: > The first is to take a snapshot of the state before making changes (perhaps > using something like re-frame's undo feature). This way, the application can > react to the changes immediately and you don't need any special logic to > pull/push data from/to global state and components can read data as they > normally would and updates can be made through handlers same as everywhere > else. To commit, you don't need to do anything[1], to revert, you throw away > the changes by reverting back to the "before edit" snapshot. > > The second technique I've used is to store the "edit mode" data elsewhere in > your global data (I've got a :scratchpad key in my app-db for things like > this, and other things like "what item in a list is selected"). You would > have to copy data to/from this the same way as with global state, so you > don't win anything in the "keeping data synchronised" department, but the > benefit over local state is that your components are dumb[2], your update > logic happens in one place and in a consistent way[3] and edits can take > part in whatever dataflow logic is applied to global state (eg re-frame's > undo; other components can subscribe to it etc). > > Now, with that said, there are times when there's no way around using local > state, in which case I DO use it. But I treat this is a technical detail > (either a performance optimisation or to get around the React controlled > input "glitch" where cursor position is lost if updating an inputs value > async). > > This is how I handle it anyway. I do agree that the coordination isn't a big > deal in this case and perhaps something like Javelin would actually make it > a non issue, but I do feel that there are significant advantages to keeping > data global and isolated from view logic and update logic. > > [1] Realistically, you probably still trigger a commit event to sync with > the server or clear the "is editing" flag and throw away the snapshot. > [2] Dumb components are less coupled, easier to understand, easier to test. > [3] This makes it easier (for me at least) to understand my code/data, makes > it easier to debug and easier to test. It also makes it easier to build > development tools (for example, I've got a (currently unreleased) app-db > viewer and handler event logger - if I store data locally, then updates are > invisible to these tools). > > On Fri, 15 May 2015 at 13:57 Jamie Orchard-Hays <[email protected]> wrote: >> >> Here's where I find local state useful and I am curious how advocates of >> centralized state handle it: >> >> A view component that allows editing. For example, click on the text and >> it changes to an input element. To me that is local state: "I'm in reading >> mode. Now I'm in editing mode." In my own app, I don't allow other >> components to change to editing mode when any other is in editing mode. This >> is a global state. So there is coordination, but it's not terrible as the >> component sets its local state and dispatches the handler for the app state >> at the same time. >> >> How do you all do it? >> >> Jamie >> >> >> >> On May 15, 2015, at 1:08 AM, Mike Thompson <[email protected]> >> wrote: >> >> > On Friday, May 15, 2015 at 10:27:46 AM UTC+10, Daniel Kersten wrote: >> >> Personally I find that moving state out of components as re-frame's >> >> subscriptions and handlers encourage is a desirable trait and would be >> >> cautious about reintroducing local state. >> >> >> >> Keeping my data in one place (and handling updates and queries through >> >> a centralised place) has made it a lot easier for me to manage complex >> >> data >> >> and logic. >> >> >> >> I've played with javelin in the past and it's a fantastic library. I >> >> quite like the idea of using it as a replacement for (or perhaps together >> >> with?) re-frames subscriptions (so reagents ratoms, really), but in my >> >> opinion reliance on local state is a mistake. >> > >> > >> > I'd like to violently agree with you. :-) >> > >> > State in the one place simplifies so much. The moment you have state in >> > multiple places, and that state needs synchronization, you have a problem. >> > >> > The strategy for solving that problem will involve either (1) things >> > watching other things for changes or (2) things telling other things they >> > have changed. The OO paradigm encourages a lot of distributed, >> > synchronized >> > state, and the "The Observer pattern" is used to handle it. >> > >> > Those that use component local state with OM, have the same issues as >> > the OO paradigm. Sometimes they use a global bus to achieve synconization >> > (things telling other things that something has changed) which is a similar >> > pattern to various OO framemworks, like PureMVC. >> > >> > In the functional programming space, the movement seems to be towards >> > FRP. Data flows into functions and out again, in something of a pipeline. >> > The structure of those flows is more declarative WRT time. >> > >> > The thing is this: synchronization of state is a pain. Have as little >> > of it going on as you can. Putting all your data in the one place >> > certainly >> > saves you from a certain class of problem -- reintroducing distributed >> > state >> > WILL cause you some grief. I'm not saying "never do it", but I am saying >> > "there'd want to be a big payoff to warrant the pain". >> > >> > -- >> > Mike >> > >> > -- >> > Note that posts from new members are moderated - please be patient with >> > your first post. >> > --- >> > You received this message because you are subscribed to the Google >> > Groups "ClojureScript" group. >> > To unsubscribe from this group and stop receiving emails from it, send >> > an email to [email protected]. >> > To post to this group, send email to [email protected]. >> > Visit this group at http://groups.google.com/group/clojurescript. >> >> -- >> Note that posts from new members are moderated - please be patient with >> your first post. >> --- >> You received this message because you are subscribed to the Google Groups >> "ClojureScript" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to [email protected]. >> To post to this group, send email to [email protected]. >> Visit this group at http://groups.google.com/group/clojurescript. > > -- > Note that posts from new members are moderated - please be patient with your > first post. > --- > You received this message because you are subscribed to the Google Groups > "ClojureScript" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To post to this group, send email to [email protected]. > Visit this group at http://groups.google.com/group/clojurescript. -- Note that posts from new members are moderated - please be patient with your first post. --- You received this message because you are subscribed to the Google Groups "ClojureScript" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/clojurescript.
