Fork me on GitHub
#re-frame
<
2016-11-08
>
nathan02:11:21

Hey everybody! I'm learning re-frame and I've got a conceptual question. Do you store all state in the global app state? What if a user fills out a field on a form, then navigates to another page, then navigates back (on a single-page app)? The form would still have what they typed in from before. The same goes for things like popover menus that maintain state of whether they're open or not. Does all that stuff go in the global app state? If so, how do you deal with resetting it when, for example, the user navigates to another page?

danielcompton02:11:00

@nathan You can choose based on what makes sense for your app. Sometimes you may prefer for form inputs to stay local to the component until they are submitted, other times you may want every character typed to update app-db

danielcompton02:11:31

https://github.com/Day8/re-com is a library which gives you these options

nathan02:11:19

Thanks, I'll take a look. I imagine there could be situations where if you started out with the state being local, you might reget that later. Any experience with that? Or maybe regrets putting everything into the app db and it becoming unmanagable?

shaun-mahood02:11:46

@nathan: I use namespaced handlers state a lot, it seems to keep things separate enough that it's not too hard to move back and forth from global to local state as needed. I've found that it moves quite a bit as I develop the app, but I primarily start with global state and move it local as it makes sense.

nathan02:11:15

@shaun-mahood Can you explain what you mean by "namespaced handlers"?

akiroz02:11:51

@nathan I put all state into the app-db in my current project. for each panel, I have a sub-map in the db and a initialize event which resets values in that sub-map / fetch data from the server.

nathan02:11:05

@akiroz Do the panel's initialize handlers need to know all the data their subcomponents may need then?

akiroz02:11:45

I'm not sure if it's a good idea but some of the components in my app actually have their own initialize/sub-map in the app-db (like a forum component)

akiroz02:11:01

but I put their data inside the panel sub-map

shaun-mahood02:11:46

@nathan: you can declare a handler as :my-ns/my-handler and the namespace doesn't have to match anything - so I tend to put in namespaces that make sense for the component, and then pull them out or rename them as I figure things out further.

nathan02:11:09

@shaun-mahood Oh right -- gotcha

nathan02:11:47

@akiroz Ok. Yeah, I've thought about doing something like that too. Thanks for the info

manishkumarmdb05:11:27

@shaun-mahood @nilrecurring can you tell me, how to use reCaptcha in any registration from?

shaun-mahood05:11:30

@manishkumarmdb: Sorry, I’ve never tried - you could try taking a look and see if anyone has done it using either react or reagent, and that would at least give you a starting point.

nilrecurring06:11:11

@manishkumarmdb never used reCaptcha sorry!

nilrecurring06:11:55

About the app-db, I too use the namespaced handlers style (makes things tidier, and some of the events are sent to Sente, which has namespaces events too), and was thinking lately of starting to add namespaced keywords to appdb

joshkh10:11:26

hi everyone, i was hoping someone could share some advice. i have a self contained, re-frame powered set of components that make up an interactive data table. it has its own state, events, handlers, etc. i have another re-frame application where i'd like to include multiple instances of the data table and dispatch events to them individually. is there a best practice for doing this?

joshkh10:11:20

my potential approach: 1. all events in the data table accept some ID as their first parameter: (reg-event-db :move-column (fn [db [_ table-id])) 2. in my main project i can mount the component with an id [my-data-table {:id (gensym)}] 3. when the component is mounted it would save the id to its internal state 4. the main application could then (dispatch [:move-column G__1]) 5. when the table sees the event it would only update its state if it has said ID

mccraigmccraig11:11:47

@joshkh do your component instances keep their state separate from the re-frame app-db ?

joshkh11:11:53

they have their own internal state, yes. but to make matters more confusing i'd like them to be able to dispatch events in the parent application 😉

joshkh11:11:10

but i think that could be easily solved with some "callback" handlers that get passed to the component instances

mccraigmccraig11:11:41

i have a similar case of components with multiple instances and app-db state, and instead of an instance-id i pass a path into app-db

joshkh11:11:18

so your main app-db might have {:components {:component-1 {:state {}}}} and when you mount the component you pass that in?

joshkh11:11:32

[:components :component-1]

mccraigmccraig11:11:46

in that case i would pass [:components :component-1 :state]

joshkh11:11:24

but when the components update that path won't they be doing it in their own internal state?

mccraigmccraig11:11:39

the component instances don't have any internal state - only app-db state - and the events for the component all have a path as their first arg

mccraigmccraig11:11:10

(and the subscriptions too)...

mccraigmccraig11:11:09

iirc i couldn't see another way around it which didn't involve passing closures around and i wanted to avoid that

joshkh11:11:21

yeah same here

joshkh11:11:03

i also don't want to pass around a huge map of overrides or callback events.

joshkh11:11:39

okay i think that helped, thanks

mccraigmccraig11:11:11

it worked out ok in the end - it wasn't quite the 'parameterize once and forget about it' approach i was looking for, but i wasn't unhappy

joshkh11:11:50

just to clarify, lets say you wanted to fire an event to just one of your components. you might do (dispatch [:highlight-column [:components :component-1] some-col-index])

joshkh11:11:38

your inner components all have a generic handler (reg-event-db :highlight-column [_ path some-col-index])

joshkh11:11:13

how does that one component know whether or not to honor the dispatch?

joshkh11:11:31

doesn't it have to check path against some internal value?

joshkh11:11:39

(sorry, i'm pretty dense, ha)

mccraigmccraig11:11:40

by the state found at path in the app-db

joshkh11:11:00

oh of course

joshkh11:11:18

that state at the path has some sort of unique value in it?

mccraigmccraig11:11:49

that path is all the unique value that is required 🙂

mccraigmccraig11:11:20

you could add something else into the state if you needed to i guess - i didn't require it

joshkh11:11:07

but doesn't (dispatch [:highlight-column [:components :component-1] some-col-index]) tell all component instances to evaluate highlight-column?

joshkh11:11:47

component-1 component-2 and component-3 would all see the event, and component-1 would have to say "yup that's me"

mccraigmccraig11:11:27

ah, no - the :highlight-column event will get handled exactly once

joshkh11:11:18

okay, right, so i've mounted the component three times but they are all still sharing the same re-frame event registry

mccraigmccraig11:11:49

yes, there is only a single event registry

joshkh11:11:22

okay i think i'll have to set up some initial test cases to wrap my head around it. in my situation the components have their own internal app-db, and i'll be requiring the component as a dependency. so i'm thinking in that case the tables each have their own app-db but their events get registered to my main application.

joshkh11:11:25

(by the process of including their namespaces)

joshkh11:11:24

for instance, requiring https://github.com/Day8/re-frame-async-flow-fx makes the effect available to the main application

joshkh11:11:07

anywho, thanks for sharing your thoughts. very helpful 🙂

shaun-mahood18:11:28

Interesting post on using Martian with re-frame - really seems to simplify things for HTTP calls - https://juxt.pro/blog/posts/advanced-martian.html

mccraigmccraig18:11:33

martian looks pretty sweet

richiardiandrea19:11:40

agree I saw it today and it really improves the testing story for re-frame apps

shaun-mahood19:11:45

I'm especially excited for what happens to things like this as spec gains maturity

richiardiandrea19:11:18

it looks like we'll just need to put pieces together for very good tooling

richiardiandrea19:11:45

whoever will have time to do it first will receive lots of kudos 🙂

mattsfrey22:11:34

Is there a quick way to change values in app-db from repl?

shaun-mahood22:11:16

@mattsfrey: You should be able to change it just like a normal atom, it's found at re-frame.db/app-db

mattsfrey22:11:39

yeah.. needed to use swap!

shaun-mahood22:11:47

Though if I were doing it at all regularly, I'd probably set up an event handler that I can pass in some data in.

shaun-mahood22:11:34

No problem, I think it's probably a good thing to forget how it's implemented most of the time - saves you from the temptation to mess with it outside of events 🙂

mikethompson23:11:23

You have a nice dirac repl available ... then you can (dispatch [:event]) at the repl. Maybe

shaun-mahood23:11:00

I guess it depends which repl - I don't think I've ever had any trouble dispatching from figwheel at least