Fork me on GitHub
#re-frame
<
2019-06-12
>
xfyre06:06:06

I’m looking for some kind of a design/architecture advice. I’m using re-frame with React Native app, and navigation is built on top of React Navigation. I ran into issues recently because I didn’t realize that React Navigation doesn’t unmount previous component on navigation stack when pushing the next one, and if two screens on navigation stack subscribe to the same data this might result in a mess. Is there any guidance/recommendations how to handle this in React Native? Besides the obvious (having a separate app-db area for each screen, with duplicated data if necessary)?

xfyre06:06:16

Another correlated question: there’s a lot of data which should be naturally shared (like network loading status). But in case of invisible mounted components this will result in a lot of unwanted reactions (for ex. if every screen subscribes to (get-in db [:app-state :loading]), and I pushed several screens onto the navigation stack). What would be the best way to handle it? Keeping those things separately for every screen would result in a lot of boilerplate code.

lepistane10:06:58

better ask in #cljsrn or #re-natal i have simple case when using react navigation but to each screen has separate data that it depends on. They don't share data. Is it required that these components share data? Maybe this is sign that they don't need to?

helios10:06:31

the channel is #cljsrn ^^

lepistane10:06:00

oh right 😄 tnx

xfyre11:06:09

@lepistane there’s a case of application context which should be retained once user pushed a certain screen on top of navigation stack (all subsequent screens may re-use data from this context) I do agree that it’s generally safer not to share this information, although this could have been convenient

xfyre11:06:16

the question is not very RN specific, actually; it’s rather about proper usage of re-frame approach

witek14:06:56

Hi. I am looking for best practices on how to build a re-frame library. For example an "auth" library which provides views and event handlers for registration, login, logout, etc. I am not sure how to pass app specific data to this library. Information like logo-url, welcome-text, supported-oauth-providers, event-to-call-after-login. Should I pass these as parameters to views? Or should I place them in the db?

witek14:06:23

What if the configuration parameters for the library are more complex and need to be functions? Is it good practice to put functions into the db so that event handlers from the library can call functions placed in the db?

oconn14:06:38

To take on one part of that question - I would not recommend putting any functions into the db. One option to get around this is to pass events as data that could be dispatched by your lib as an effect

oconn14:06:10

on-success and on-error in this example are dispatched by the lib and mapped to registered handlers

witek16:06:12

What is the argument for not putting functions into db? Because this seams to make things very difficult. For example the library verifies the user name while registration, while each application can implement it's own username validator. Therefor I would put auth.validate-fn into db and the library could call this function while the user is typing or after form submit. Using events or effects for this seams more complicated. What am I missing here?

lilactown17:06:55

using the re-frame event system is more idiomatic and allows consumers to inject and inspect what’s going on inside your library better using normal re-frame machinery

lilactown17:06:36

I’m not sure why you would need to put functions in your app-db anyway, rather than just closing over them when you register your libraries events / effects / subscriptions

lilactown17:06:16

the app-db should be for your application domain data. putting things like functions in it seems wrong

lilactown17:06:57

one concrete problem with putting functions in the app-db is it prevents consumers from easily serializing the DB to e.g. localStorage or some other persistence as EDN

oconn17:06:22

^ yes - So I would shy away from using a lib that stores functions in the global db because of serialization - I persist parts of app state in localStorage / send it to an error reporting services and that typically causes problems - also rehydrating an app with that state is problematic.

witek18:06:22

Thank you for your useful tips. So how to deal with optionality in this scenario? Say, my auth library supports this custom user name validation from the using app - but it is optional, the app does not have to provide a custom validation. In this case the library should use the default user name validation. Is there a way to ask re-frame if a specific event handler or a specific effect exists before calling it?

witek18:06:33

I see that re-frame events are the right way to model the "application flow". But it seams that I want to create a library, where the application which uses this library needs to "configure" the application flow. So I am not sure if such configuration of the application flow should also be implemented as re-frame events/effects.

oconn19:06:14

It’s hard to tell without seeing more or talking though the full workflow - I wonder if you could initialize the form component with the optional custom validators and then on submission dispatch an event? If the configuration is going to be used across multiple views / components then you could store the custom validators in an atom when the lib is initialized. It’s hard to tell what the best approach is though without more information.

witek19:06:45

My problem is, that my ui library (or libraries) have a lot of such extension points, where the library implements reusable components login/registration, error rendering, support feedback, in-app user comments, forms with validators, menus with hotkeys and so forth. these libraries need configuration and customization from the apps. So I am looking for the idiomatic way how such library extension points should be implemented.

oconn19:06:19

so re-frame itself uses a global registrar https://github.com/Day8/re-frame/blob/master/src/re_frame/registrar.cljc that all events / subs / cofx / and fx function handlers get stored in. When the handlers get triggered [:dispatch [:some-event {:data {}}]]it pulls the handler out of the registry. You could setup your library in a similar way that stores all your configuration data as data in re-frame, and have pointers to user defined functions / etc.. Once again, just an idea going off the information at hand.

witek20:06:29

Thank you for this one 🙂

witek20:06:59

How about this: The library does not register events on load. Instead it provides a function initialize which my app has to call. This function gets a configuration map with all customization values and functions. Then it registers it's re-frame events and effects, which have acces to the enclosed configuration map. You think this is a valid approach?

steveb8n00:06:14

there’s an example of this using Integrant here https://223kazuki.github.io/re-integrant.html

lilactown22:06:29

that sounds reasonable