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.

Reply via email to