I am getting the following errors from https://github.com/endrebak/everclear/blob/working/src/cljs/everclear/dag/core.cljs, the most important of which I guess is
react-dom.development.js:68 Warning: React has detected a change in the order of Hooks called by everclear.dag.core.graph_page. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: <https://reactjs.org/link/rules-of-hooks>
Previous render Next render
------------------------------------------------------
1. useState useState
2. useRef useRef
3. useEffect useEffect
4. undefined useState
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Any hints on how to debug?@endrebak85 hooks have very specific rules. you must move the useState
call into the inner fn
or remove that inner fn entirely
also your use of those hooks is incorrect. you definitely should not be calling set-graph
as part of the render
Hmm, I guess the set-graph
can just be in a function of its own that listens to the sub since it does not need to add any hiccup, it just modifies an existing element. Thanks. Will try some more.
you are trying to mix 2 entirely different rendering models. so you must read up on refs in react and them use them in a useEffect hook to wire up the graph stuff
or go without hooks and just refs, that is fine too
the when-let is a problem as well. if the subscribe returns nil on the first try it'll never update if it becomes available later
Thanks. I was just copying the luminus
template which uses the following:
(defn page []
(if-let [page @(rf/subscribe [:common/page])]
I thought it was a way to postpone the showing page until the data was ready.does that have the inner anon fn? I guess not?
No π
Thanks. I did not know I was mixing them π Now I've gotten it to work with refs.
I am trying to translate the following code into ClojureScript (the javascript is a simplified version of https://github.com/ArquintL/d3-dag-example/blob/master/src/app.js):
const reader = d3_dag.dagStratify()
const dag_data = await d3.json(`<https://raw.githubusercontent.com/erikbrinkman/d3-dag/master/examples/grafo.json>`);
reader(dag_data)
This is my attempt:
reader (d3-dag/dagStratify.)
data (->
(d3/json "<https://raw.githubusercontent.com/erikbrinkman/d3-dag/master/examples/grafo.json>")
(.then reader)) // failing line
I get the error:
Uncaught Error: can't stratify empty data
Am I doing something obviously wrong in my handling of https://clojurescript.org/guides/promise-interop or what?On the js side you don't calling new
on dagStratify(), so in cljs you dont need to use the .
in (d3-dag/dagStratify.)
Thanks, that seemed to do it π
This is the first time I have to use go-blocks and the first time I've had to deal with promises, so I am a little confused. If I want to translate the following into a go-block, how would I do it?
const reader = d3_dag.dagStratify()
const dag_data = await d3.json(`<https://raw.githubusercontent.com/erikbrinkman/d3-dag/master/examples/grafo.json>`);
reader(dag_data).then(d3_dag.sugiyama())
I've gotten this far:
(let [reader (d3-dag/dagStratify)
sg (d3-dag/sugiyama)
dunno? (go
(let [data (<p! (d3/json "<https://raw.githubusercontent.com/erikbrinkman/d3-dag/master/examples/grafo.json>"))
dag-data (reader data)
layout (<p! (sg dag-data))]
layout))]
I think everything but layout (<p! (sg dag-data))
is correct. But I am having a hard time translating this call:
reader(dag_data).then(d3_dag.sugiyama())
@endrebak85 don't waste your time on a go block for this, just chain the promises
(-> (d3/json "<https://raw.githubusercontent.com/erikbrinkman/d3-dag/master/examples/grafo.json>")
(.then reader)
(.then (d3-dag/sugiyama)))
from the gist:
loadDag(source)
.then(useArquint ? arquint() : sugiyama())
.catch(console.error.bind(console));
async function loadDag(source) {
const [key, reader] = sources[source];
const dag_data = await d3.json(`<https://raw.githubusercontent.com/erikbrinkman/d3-dag/master/examples/${key}.json>`);
return reader(dag_data);
}
It looks like loadData
also returns a Promise
(based on the immediate call to .then()
). The last line of loadData
is reader(dag_data)
so your code equivalent of this line would need its own (<p!)
call to yield the result:
(go
(let [data (<p! (d3/json "<https://raw.githubusercontent.com/erikbrinkman/d3-dag/master/examples/grafo.json>"))
dag-data (reader data) ;; try wrapping in (<p! )
layout (<p! (sg dag-data))] ;; not sure if call to sg returns a promise?
layout))
β¦or chaining then
calls might be cleaner.Much obliged!
though you probably want error handling
and then depending on how far away the error handling needs to be, or how many handlers there may need to be
you may or may not want to do this w/ promises
but if it's not involved I agree chaining is fine
https://stackoverflow.com/questions/26076511/handling-multiple-catches-in-promise-chain
I much prefer go + try/catch + ex-info + causes
I want to call the .links
function on the object in a promise. I think I've tried every variation of the below, but nothing works
(.then graph.links) ;; (-> graph (.then (.links)) ;; ...
What is the correct way to do it?
Below the promise-wrapped graph object is shown. It has a .links
method, but I do not know how to get at it.(.then (fn [obj] (do-stuff-with (.-links obj)))
or rather (.links obj)
, looks to be a function
Thanks. In https://github.com/ArquintL/d3-dag-example/blob/master/src/sugiyama.js#L76 I'm trying to convert it is a function, but when I try to use it as a function, I get the error: Uncaught (in promise) TypeError: obj.links is not a function
. Any ideas what might be wrong?
console.log the item and see if it resembles what you expect
I have done so:
{dag: LayoutDagRoot, width: 5.83843708165997, height: 8}
dag: LayoutDagRoot
dagRoots: (6) [LayoutDagNode, LayoutDagNode, LayoutDagNode, LayoutDagNode, LayoutDagNode, LayoutDagNode]
__proto__:
...
links: Ζ links()
So it should have a link method AFAICS.can you paste the exact code you are using to try to call it?
Sure:
(.data (-> graph (.then (fn [obj] (js/console.log obj) (.links obj)))))
that looks quite different that .data(dag.links())
above. and you're sure links: f links()
is on the top level and not nested in the obj
you are logging?
graph also probably isn't a promise? what is graph? maybe you just want (.data (.links graph))
?
yeah from that code sample there's no promise stuff going on
would help to have your full code, seems like you are making a couple mistakes
https://github.com/endrebak/everclear/blob/working/src/cljs/everclear/dag/draw.cljs
Rendering a DAG is about the only thing I need to do in JS so I have not started reading properly about JS/ClojureScript yet. I'd love to include a Clojure-project in my PhD, but I am working against a tight deadline, so I am just trying to get stuff to work quickly.
there's no use of then
in the sample you are following. why did you introduce that
Because I could not find a .link
function and I assumed it was because it was wrapped in a promise.
And if I try to log that graph, I am told it is a promise: [object Promise]
.
so their dag is passed in. not sure how they got it, but perhaps they are calling (.then dag draw)
.
The data is loaded with d3.json
which returns a promise so I guess whatever they do after that also happens in a promise.
But yeah, everything happens within a .then
: https://github.com/ArquintL/d3-dag-example/blob/master/src/app.js#L18 That sugiyama
function is what contains all the calls.
so their function takes the value resolved from a promise, but you are passing that promise in. you'll need to correct that
I thought once a promise always a promise. I looked for a way to unpack/deref a promise, I guess this is it: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
no, you (.then render-graph)
. the variable you named dag
is actually the dag promise, so the only way to get the actual dag is to .then it and access it async
There's also the <p!
macro in cljs.core.async for 'awaiting' Promises AFAIK (tagged experimental though)
(defn render-graph [data]
...)
(defn graph-page []
(-> (d3/json "<https://raw.githubusercontent.com/erikbrinkman/d3-dag/master/examples/grafo.json>")
(.then render-graph))
[:div
[:h1 "hiya"]])
this is still widely incorrect regarding the react use but at least in render-graph
you don't have to worry about promises at all anymore.
Thanks all, now I am getting closer. I just need to find out how I'm mishandling react. Btw, this is for a project I'm hoping to publish in bioinformatics (or at least biorxiv) by the end of the year. I will discuss Clojure in it too. What channel would be most appropriate for asking about feedback on my discussion/summary of Clojure?
Thanks. I should learn more about <p!
too π
if it's a general "about clojure" type thing, probably off-topic. if you write an article there's an #news-and-articles channel as well
I cannot find any documentation about the use of curlybraces below (taken from here: https://github.com/ArquintL/d3-dag-example/blob/master/src/sugiyama.js#L102):
({x, y}) => `translate(${x}, ${y})`)
;^^^^^
What is the correct way to translate this?
In a node repl, that function does not seem make sense, but I might be invoking it incorrectly:
> var f = ({x, y}) => x + y
undefined
> f(1, 2)
NaN
Thanks. Weird that googling "anonymous function js curly braces" returned nothing relevant
really not specific to anonymous function in any way
let {x, y} = obj;
is also valid
this is destructuring for a JS obj, can't do that in CLJS. but (fn [obj] (let [x (.-x obj) y (.-y obj)] ...))
works
In JS that's destructuring a single object argument to get keys x
and y
from the object and bind them as local vars to the same names as the keys
So in JS you'd call f
like this:
f({x: 123, y: 456})
cljs has clojure map destructuring in the argslist, but unfortunately (as @thheller points out) you can't destructure a JS object in cljs in the argslist, you'll have to bind it to a local arg name and pull out those values yourself
an equivalent non-destructured JS implementation of f is
const f = (obj) => obj.x + obj.y
Iβm starting a REPL with clj -M --main cljs.main --repl
and using Firefox (88.0.1 on Mac) as my default browser, but the REPL immediately freezes as soon as I try to evaluate anything at all, and I can only quit it by Ctrl-C (not Ctrl-D). Deps.edn only has ClojureScript 1.10.844, nothing else. This hang doesnβt happen with Chrome, but whatβs wrong with ClojureScript in Firefox?
@ntuggy just tried with 88 no issues
and 88.0.1 as well
Thanks for checking. Any ideas on figuring out where the problem is? Nothing shows up in the browser console, even in Safe Mode. (Also, itβs not just Firefox; I started with Pale Moon, a Firefox fork, and only switched thinking it might be some obscure compatibility bug.)
hrm I really don't know - something environmental for sure
if you just need/want to dev ClojureScript this doesn't seem essential
i.e. dev in Chrome - test all browsers (no REPL)