I have a subscription :show-payme that is set to true. When it is set to true, a div is mounted:
(if @(subscribe [:show-payme]
[:div {:id "card-element"}]
)
I have an fx event that returns the following:
{:db {:show-payme true}
:dispatch [:load-stripe]}
the load-stripe fx event contains the following:
(.mount card-element "#card-element")
The problem is that the .mount is being called before the #card-element div ever mounts on the page, which is causing the #card-element Element Not Found error. How do I get around this?I want the #card-element to be mounted before the load-stripe dispatch is called
That's what React lifecycle methods are for. Unless the JS library requires DOM elements' IDs, you should never use them. Instead, set a React ref in :reagent-render
and run the JS code that uses that ref in :component-did-mount
.
I've never used :reagent-render. Can you please show a minimal example what you mean?
I don't see how to mount the stripe element into that empty div without using the id. I instead removed the load-stripe dispatch, and changed to the following:
(def load-stripe (with-meta identity {:component-did-mount (dispatch [:load-stripe])}))
[load-stripe [:div {:id "card-element"}]]
But I get:
Uncaught (in promise) IntegrationError: We could not retrieve data from the specified Element.
Please make sure the Element you are attempting to use is still mounted.
at new t (https://js.stripe.com/v3/:1:10981)
at _o (https://js.stripe.com/v3/:1:53784)
at e._handleMessage (https://js.stripe.com/v3/:1:60201)
at e._handleMessage (https://js.stripe.com/v3/:1:27512)
at https://js.stripe.com/v3/:1:58803that load-stripe wrap is supposed to trigger the :load-stripe dispatch when the container div is mounted
it works like the technique in the GitHub link but I find it more elegant
> I don't see how to mount the stripe element into that empty div without using the id. Read about React refs and look around for examples.
{:component-did-mount (dispatch [:load-stripe])}
is completely wrong. It has to be a function, not a result of the call to dispatch
.
I meant #(dispatch ...)
And don't load Stripe in an effect handler, since it requires an element. Just load Stripe in :component-did-mount
. You don't need IDs for that.
You never need IDs with React for something that's able to receive instances of DOM elements.
how do I do that? (.mount card-element "#card-element") becomes what?
(.mount card-element the-element)
, I imagine.
so I did {:component-did-mount #(dispatch [:load-stripe %])} and replaced the id with that new parameter
but that gives me:
Uncaught IntegrationError: Invalid DOM element. Make sure to call mount() with a valid DOM element or selector.
at new t (<https://js.stripe.com/v3/:1:10981>)
at t.<anonymous> (<https://js.stripe.com/v3/:1:107809>)
at t.mount (<https://js.stripe.com/v3/:1:27512>)
at eval (<http://localhost:3000/js/cljs-runtime/vendo.events.js:107:14>)
at eval (<http://localhost:3000/js/cljs-runtime/re_frame.std_interceptors.js:157:236>)
at re_frame$std_interceptors$fx_handler__GT_interceptor_$_fx_handler_before (<http://localhost:3000/js/cljs-runtime/re_frame.std_interceptors.js:167:4>)
at Object.re_frame$interceptor$invoke_interceptor_fn [as invoke_interceptor_fn] (<http://localhost:3000/js/cljs-runtime/re_frame.interceptor.js:224:88>)
at Object.re_frame$interceptor$invoke_interceptors [as invoke_interceptors] (<http://localhost:3000/js/cljs-runtime/re_frame.interceptor.js:263:37>)
at Object.re_frame$interceptor$execute [as execute] (<http://localhost:3000/js/cljs-runtime/re_frame.interceptor.js:380:108>)
at Object.re_frame$events$handle [as handle] (<http://localhost:3000/js/cljs-runtime/re_frame.events.js:93:22>)
That's not the correct usage. If someone that tries to help you asks you to do something, please do that. In this case, please read about React refs and look for ref examples in Reagent. I have already given you absolutely all information that you need to make it work.
"Refs are created using React.createRef()
and attached to React elements via the `ref`attribute"
But we're not supposed to use the React object, right?
Ehm, no? I don't know where you got that idea, but it's absolutely fine to use React objects.
okay this is the way to do it:
<https://github.com/reagent-project/reagent/issues/5>
I think
I like my way using the id, but I don't know why I'm getting the error though. The div is mounted and then the dispatch is being triggered.
that card-element id div is supposed to be in the dom before the (.mount card-element "#card-element") is called
yet I get the error to make sure that #card-element div is still mounted
Hi there, I have a small state management challenge: I'm making an app for a robot that feeds fishes, the robot travels between the pools, that are shown as a grid of elements while the robot is shown as an icon. Initially, I just let the robot appear and disappear in different pools when its position changes, so the robot-icon component was managed by each pool. But then I thought it could be fancier to show the robot moving between the pools. So I took the robot-icon component out of the pool, and let the pools-map component trigger a function to reposition it whenever needed, and this way the movement can be animated. There is one problem: When screen get resized, the robot position changes. So another function is needed to reposition it and this seems like trouble. Now, I may go back to the blinking robots solution, as the animation is not that important, but I think its an interesting problem. What do you think is the way to do it? Edit: How it is related to re-frame? The robot position(which pool it should be in) is obtained from an event subscription, And the app uses breaking-point so events are dispatched when the window size changes.
Not sure how it's related to re-frame. Either way, you can store the robot's position as percentages. It will work, unless window size changes also cause layout changes.
Is it possible to query the list of registered subscriptions or the list of registered events from the public re-frame API? I’m reading event and subscription keys in from overlapping datasets, and want to check whether they have already been registered. If not, what would happen
if I made a duplicate registration… OK I can try and see..
It would just override the previously registered one, with a warning in JS console.
The public API to check would be (re-frame.registrar/get-handler :sub my-id)
for subs. For events, replace :sub
with :event
.
The robot position(which pool it should be in) is obtained from an event subscription, And the app uses breaking-point so events are dispatched when the window size changes. So I thought maybe it should be a combination of these subscription. Maybe using percentages is enough though :)
Yeah the latest version of re-frame will give you a warning on initial application load if handlers are overwritten (but not on hot reload)
(Older versions of re-frame gave overwrite warnings even on hot reloading, which is noisy and less helpful)
re-frame.registrar/get-handler
is not public API (but it will work for exploratory purposes)
Just to make sure it's clear - there will be no warning after the initial app load even if you register a handler under an existing ID deliberately and not as a part of hot reload.
@mikethompson Oh. But how can one tell what's public API and what's not?
Thanks @mikethompson @p-himik. This could happen in production code, which is why I want to make sure I’m handling the possibility correctly.
I guess I can only access re-frame.registrar by adding it to the classpath.
• in addition to re-frame.core I mean.
re-frame's jar is on the classpath already. You just require re-frame.registrar
in your namespace.
@p-himik re-frame.core
is the public API
That's the part we try not to break
you could also cheat and use css 🙂
let the browser handle the transitions
no need to do that imperatively, if all you want is to animate the position change
(not really cheating, but you get what i mean)
Well, If i want the element to change its position to another element's position, I need to set the top of my icon to the target's http://getBoundingClientRect.top I do this set in a react hook. But this position is given in pixels, and changes when the screen resizes. I think that the resizing problem is mostly because I didn't got the css right, because mixing relative and absolute positioning is confusing. Another option is using some sleight of hand - When the icon changes pool, move it there, then remove it, and add a new icon in the new pool. this should allow its position to be relative, and avoid the trouble of mixing absolute position.
Why would global interceptor be useful?
Some discussion in the original issue: https://github.com/day8/re-frame/issues/570
So how would you track a value under :x with a global interceptor?
With the on-changes
standard interceptor, for example.
Hey all. I'm new to re-frame and I have to write tests for my event handlers. I had a few doubts: How do I use the day8.reframe.test library in my file? (I tried using this but it says The required namespace is not available 😞 ) What are test fixtures?
I’ve tried re-posh
but don’t really love it. Thoughts on putting a posh
db inside of re-frame
? Or generally speaking any atom
inside app-db
?
why put it in the app-db?
so many components, function, etc. use posh
. you’re right, it could be its own global as well. but I’m not sure that’s the best option
yeah, I don’t really see the benefits of putting it in the app-db
if you’d like to use re-frame’s event/effect system, you can write an effect that writes to a posh db instead
cool, thanks @lilactown
Would you happen to have any input on https://clojurians.slack.com/archives/C07V8N22C/p1592497389093700
you've got transforms too!
can set a position with transform and transition will perform the.. er.. transitions
Can you mix re-posh and re-frame? For example having a re-frame subscription depending on a re-posh subscription?
AFAIK a re-posh sub is the same a re-frame sub so you should be able to compose them the same way you would any other re-frame sub
how to find the line number of the re-frame code that throws the error:
[Error] Error: ["unrecognized request format: " nil]
(anonymous function) (re_frame.router.js:6)
(anonymous function) (re_frame.router.js:359)
(anonymous function) (re_frame.router.js:425:110)
(anonymous function) (re_frame.router.js:552)
(anonymous function) (re_frame.router.js:291)
(anonymous function) (re_frame.router.js:383)
(anonymous function) (re_frame.router.js:425:110)
G__67540 (re_frame.router.js:336)
(anonymous function) (goog.async.nexttick.js:98)