This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-12-28
Channels
- # announcements (13)
- # babashka (7)
- # beginners (35)
- # calva (23)
- # chlorine-clover (6)
- # cider (12)
- # clj-kondo (6)
- # clojure (31)
- # clojure-dev (20)
- # clojure-europe (4)
- # clojure-norway (4)
- # clojure-uk (1)
- # clojurescript (62)
- # fulcro (6)
- # google-cloud (1)
- # lsp (2)
- # malli (13)
- # meander (6)
- # music (1)
- # off-topic (19)
- # practicalli (2)
- # re-frame (7)
- # reagent (25)
- # reitit (5)
- # releases (1)
- # reveal (3)
- # shadow-cljs (90)
- # tools-build (18)
- # tools-deps (1)
here's what the error boundary code looks like
(defn error-boundary [comp]
(js/console.log comp)
(let [error (r/atom nil)]
(r/create-class
{:component-did-catch (fn [this e info]
(js/console.log "sending error to sentry")
(js/console.log this)
(js/console.log e)
(js/console.log info))
:get-derived-state-from-error (fn [e]
(reset! error e)
#js {})
:reagent-render (fn [comp]
(js/console.log "does this render?" error)
(if @error
[:div
"Something went wrong."
[:button {:on-click #(reset! error nil)} "Try again (reload page)"]]
comp))})))
and the component where I'm using it
(defn dataview-component
[]
[error-boundary
[:<> [dataview-menu]
(let [{path :path, :as match-data} @match]
(throw (js/Error. "error info"))
[:div#content.full-page-fixed
[:div.container-wide
[:div#dataset-view.cfix
[:div.tab-container.dataset-tabs [tab-bar path]
(when match-data
(let [view (:view (:data match-data))] [view match-data]))]]]])]])
I use the exact same thing but with one potentially crucial difference - my error boundary is not something that can accept a child. But rather, it's the main component itself.
In you case, I think if something goes wrong in dataview-component
itself, the error boundary will not work - simply because it didn't even have the chance to be turned into an element yet.
Ah, and you do throw
in that component - so that's why. I don't think an error boundary would catch anything in that case, as you yourself observe. Try moving its child into its own component and then using something like
[error-boundary [child-that-throws]]
@U2FRKM4TW that worked 😃
the part I don't undestand in your explanation here is > simply because it didn't even have the chance to be turned into an element yet
I wonder if there's documentation or code I can read that would help me understand better when things are turned into elements
For a Hiccup vector to become a React element, Reagent has to get that vector first. And your function simply does not return a vector - it throws immediately. The error boundary component is never encoded in an element, it's never instantiated. So it can't catch anything.
Well, the best starting point is to read React's documentation on the difference between components, elements, and instances. Once that understanding is achieved, perhaps Reagent documentation has something about turning Hiccup into elements. I've been using Reagent for quite some time now so at this point I more often just read the source code itself.
Not long at all if you start doing that early. :) Besides its reactive part (stuff in the reagent.ratom
namespace), it's rather easy to follow actually.
I am trying to convert a javascript sample This is the original code
function MyComponent() {
const map = useMapEvents({
click: () => {
map.locate()
},
locationfound: (location) => {
console.log('location found:', location)
},
})
return null
}
function MyMapComponent() {
return (
<MapContainer center={[50.5, 30.5]} zoom={13}>
<MyComponent />
</MapContainer>
)
}
and this is my code I guess I am using reagent.core/as-element
wrong way
(ns tools.adapters.leaflet
(:require
[reagent.core :refer [adapt-react-class as-element]]
["react-leaflet" :as leaf]))
(def map-container (adapt-react-class leaf/MapContainer))
(defn map-events [e] (as-element (leaf/useMapEvents e)))
(defn maplayer []
[map-container {:center [51.505, -0.09] :zoom 13 :style {:height "300px"}}
[tile-layer {:url "https://{s}.}]
[map-events {:click #(js/console.log %)}]])
Sample source
https://react-leaflet.js.org/docs/api-map/#usemapeventsHave you read the documentation I mentioned?
as-element
is, as it states in its docstring, a function to convert a Hiccup vector into a React element. But you're passing a result of a hook call to it, which cannot possibly be a Hiccup vector in this case.
You need to create a function component, use a hook there just as you would in React, and then use that function component.
I see. I did read the documentation but I couldn't figure it out. I never used react before clojurescript maybe that why I am failing to figure it out. I'll try as you suggest.
Ah, yeah. Reagent relies on React in more than just its internal workings - it's a semipermeable abstraction, so knowing a fair bit of React will significantly increase your chances of overall success with Reagent. It also has a very nice documentation, so I would definitely recommend reading it when time allows.