drapanjanas / re-natal

Bootstrap ClojureScript React Native apps
MIT License
1.22k stars 99 forks source link

Figwheel inferior to Hot Reloading? #58

Open danielbraun opened 8 years ago

danielbraun commented 8 years ago

I'm facing an annoying issue with WebViews. When using figwheel, each time I save (and thus hot reload the app) all webviews in my app are "refreshed". It's not the case when using JavaScript react native projects with Hot Reload enabled. The UI tree is updated, and WebViews are not reloading their pages.

re-natal + figwheel + save = web view is refreshing vanilla react native + hot reload + save = web view is not refreshing

I played around with a google maps examples. simulator screen shot 24 jun 2016 22 20 34

pvinis commented 8 years ago

why was this closed? did you figure it out?

danielbraun commented 8 years ago

I haven't figured it out. It's just been a while and no-one commented. I can re-open it if you're facing it yourself as well.

pvinis commented 8 years ago

I am not facing the same thing, but I am wandering what the differences are on a deeper level, so I thought I would get some extra insight from this issue. but like you said, noone commented.

carocad commented 7 years ago

@danielbraun just adding myself to this conversation as I am interested as well.

I am facing a similar problem with mapbox's react-native wrapper. Whenever I save the file using Cursive + figwheel + re-natal my whole apps gets refreshed, not just the part that I just changed :(

I am not sure if this is a react-native problem, on my side or on the cljs stack since when I tried developing apps with figwheel in a browser everything worked as expected (no state lost on reload)

seantempesta commented 7 years ago

Check the dev menu. I've noticed react native starts out with Live Reload enabled by default these days and you have to disable it.

https://facebook.github.io/react-native/docs/debugging.html On Thu, Mar 23, 2017 at 1:42 AM Camilo Roca notifications@github.com wrote:

@danielbraun https://github.com/danielbraun just adding myself to this conversation as I am interested as well.

I am facing a similar problem with mapbox's react-native wrapper. Whenever I save the file using Cursive + figwheel + re-natal my whole apps gets refreshed, not just the part that I just changed :(

I am not sure if this is a react-native problem, on my side or on the cljs stack since when I tried developing apps with figwheel in a browser everything worked as expected (no state lost on reload)

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/drapanjanas/re-natal/issues/58#issuecomment-288480552, or mute the thread https://github.com/notifications/unsubscribe-auth/AAsVBI3ixFv9xQ6fJF2-wks6D44WlGS5ks5roV1mgaJpZM4I-Dgi .

-- Sean

carocad commented 7 years ago

@seantempesta I checked it on my phone and it does not look as if the Live Reload is enabled by default.

On the dev menu in my phone it says Enable Live Reload so I guess that means that it is not enabled.

drapanjanas commented 7 years ago

Maybe the problem is how figwheel reload callback is implemented in re-natal. There is a reloader component which wrapps the application root component. This component re-renders when cnt ratom changes, which is on each fighweel reload. The intention was to cause component tree startig from app root to re-render if some code reloaded by figwheel. But, it seems, the actual effect is that components are unmounted and mounted again, which causes loosing their internal state.

carocad commented 7 years ago

@drapanjanas I think you are correct. After some experiments, I found out that if I keep a reference (through react's ref property) to the component, then I can keep the state even after a reload from figwheel.

I guess the problem is that unlike react, react-native is much more welcoming of internal state (maps components use that a lot) which obviously gets resetted after fighwheel unmounts and remounts the components :(

carocad commented 7 years ago

for your interest: here is the blog post from facebook on React Native: https://facebook.github.io/react-native/blog/2016/03/24/introducing-hot-reloading.html

from the blog:

In a nutshell, his solution works by creating a proxy for every single React component on transform time. The proxies hold the component's state and delegate the lifecycle methods to the actual components, which are the ones we hot reload:

So they actually avoid reloading the real component and instead keep the inner state separated so that on reload it wont get lost. I guess for React Native hot reloading is in fact better than figwheel :/

carocad commented 7 years ago

An update after some discussions in the cljsrn channel. Although hot reloading seems to work better for stateful components, it doesnt work well with stateless ones (a.k.a functional components). That would explain why maps work better with hot-reloading whereas things like text and views just never update (based on my own experience).

Furthermore the rn dev team doesnt seem too motivated to solve such issues in the near future. So it seems that figwheel is still ahead of the rn hot reload feature. I think that if we could avoid this full component reload on the root then we would be able to keep the state of those components.

@drapanjanas would you mind telling us why does figwheel needs to have this reload on the root element? I tried disabling it but then the app just never updated :(

References:

drapanjanas commented 7 years ago

Well, figwheel just recompiles and reloads changed files. It is a generic tool and is not aware of react or whatever other libs are used in the app. So it is not given that app is reloadable, but with react it is usualy the case. Writing Reloadable Code describes some tips. You can see what files were reloaded in console log - it is the changed namespace and all namespaces which imports it. I think, for the webapp reload just works because in core namespace we usually have code which mounts the root component to the dom, so we get app reloaded becuase this namespace is reloaded every time any imported namespace have changed. In RN I was not able to make it work in a similar way. So, it all ended up having a special namespace env.ios.main which wraps the app-root component which is re-rendered on every reload using :jsload-callback hook provided by figwheel. In reagent there is also a force-update-all but it seems not working in RN I think because we do not mount root component the "standard" way as in webapp.

So, when you remove the code of :jsload-callback, the reload just stops working. We could try thinking of something more clever to improve it, but I think it is important that we keep it all locked in special env.* namespaces and not let reload-specific code suck in to the real app namespaces.