Visual debugging of components (#17729)

* feat: debug/show components from the REPL

* ref: some renames and cleanup

* chore: removed comments/imports

* feat: added remount on every eval & small changes

* doc: added tip to debugging doc

* doc: formatting

* doc: more formatting

* fix: fixed docs and other review comments

* fix: moved & renamed into the dev.component-preview ns

* style: adjusted debugging readme spacing

* fix: removed trailing line
This commit is contained in:
Lungu Cristian 2023-10-27 13:14:01 +03:00 committed by GitHub
parent 2aeafa30bd
commit 954373105d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 86 additions and 0 deletions

View File

@ -99,3 +99,38 @@ Also to inspect logs in a more flexible manner, instead of the strict output fro
adb logcat | grep 'ReactNativeJS\|StatusModule\|GoLog'
```
### From @clauxx (visual debugging):
When building/fixing/refactoring components, it can be annoying to set-up the component for instant visual feedback (i.e. finding it in the UI when fixing/refactoring; finding a place for it when building from scratch). Very often if the location of the screen containing your component nested deeply in the app, you might have to do a lot of repeated navigation, nevermind logging in every time the app reloads (even with fast refresh disabled this happens quite often).
To alleviate this discomfort and make the development cycle more *pleasant*, you can use one of the following options (*_both of which involve the ... REPL ༼ つ ╹ ╹ ༽つ, so make sure you have that set-up with your IDE/editor_*)
#### REPL-ing to a screen
This one is straightforward, just evaluate a navigation dispatch form from anywhere:
```cljs
(comment (rf/dispatch [:navigate-to :your-favorite-buggy-screen]))
```
> TIP: you can run this from an untracked user namespace `(ns user)`, from which you can experiment or interact with the REPL. This is where I usually keep my development navigation forms.
#### REPL-ing a component
This is also straighforward, but there are some small differences. Just like above, we only have to evaluate a dispatch form, as follows:
```cljs
;; example debugging a quo component, although it could be any other component e.g. from the `status-im2` ns.
(comment (re-frame/dispatch [:dev/preview-component
[quo/slide-button
{:track-icon :face-id
:track-text "preview component example"
:customization-color :blue
:on-complete identity}]]))
```
When evaluated, a full-screen bottom sheet will appear with your component inside. You can make changes to the props or the component internals and re-evaluate the changed forms, after which the component will be re-mounted without running a reload (unless you save the file). Other times it's quicker to just hit save and the component will be reloaded as usual (except for the props you evaluated, which have to be re-evaluated when changed).
> TIP: You can have multiple versions of the component as separate comments to check for the component variations
> TIP: You can leave `comment` blocks at the end of component files (other than quo, since can be previewed in other ways) with usages of components, which other developers can use for visualisation/testing.

View File

@ -0,0 +1,25 @@
(ns dev.component-preview.events
(:require
[quo.core :as quo]
[re-frame.core :as re-frame]))
(def preview-screen-name :dev-component-preview)
(when js/goog.DEBUG
(re-frame/reg-event-fx :dev/preview-component
(fn [{:keys [db]} [[component-tag props & args]]]
(let [view-id (:view-id db)
;; NOTE: re-render on every evaluation e.g. reset component state without changes
component (into [component-tag (assoc props :key (random-uuid))] args)
navigate? (not= view-id preview-screen-name)]
(cond-> {:db (assoc db :dev/previewed-component component)}
navigate? (assoc :fx [[:dispatch [:navigate-to preview-screen-name]]]))))))
;; Usage example
(comment
(re-frame/dispatch [:dev/preview-component
[quo/slide-button
{:track-icon :face-id
:track-text ":debug-component example"
:customization-color :blue
:on-complete identity}]]))

View File

@ -0,0 +1,16 @@
(ns dev.component-preview.view
(:require
[react-native.core :as rn]
[utils.re-frame :as rf]))
(def ^:private container-style
{:flex 1
:padding-horizontal 20
:padding-top 80
:align-items :center})
(defn view
[]
(let [component (rf/sub [:dev/previewed-component])]
[rn/view {:style container-style}
(when component component)]))

View File

@ -1,5 +1,6 @@
(ns status-im2.navigation.screens
(:require
[dev.component-preview.view :as component-preview]
[status-im.ui.screens.screens :as old-screens]
[status-im2.config :as config]
[status-im2.contexts.add-new-contact.views :as add-new-contact]
@ -272,6 +273,11 @@
{:modalPresentationStyle :overCurrentContext})
:component scan-address/view}]
(when js/goog.DEBUG
[{:name :dev-component-preview
:options {:sheet? true}
:component component-preview/view}])
(when config/quo-preview-enabled?
quo.preview/screens)

View File

@ -147,3 +147,7 @@
;;wallet
(reg-root-key-sub :wallet/scanned-address :wallet/scanned-address)
(reg-root-key-sub :wallet/create-account :wallet/create-account)
;;debug
(when js/goog.DEBUG
(reg-root-key-sub :dev/previewed-component :dev/previewed-component))