Fork me on GitHub
Adriaan Callaerts08:11:20

Hi all! This is probably a straight-forward question, but I've done some googling and can't seem to hit the right keywords to get the answer I need: how would I require and then use a reagent atom in a cljc namespace?


You need reader conditionals so that that code exists for CLJS but doesn't exist for CLJ.

Adriaan Callaerts08:11:00

I figured something like that, but then I can't seem to find out how to combine this with some other requires.

(ns fleet-frontend.fe.components.filter
  (:require-macros [cljs-css-modules.macro :as css])
  (:require [oops.core :refer [oget]]
            [fleet-frontend.fe.components.icon :refer [search]])
     (:refer-clojure :exclude [atom])
     (:require [reagent.core :refer [atom]]))
  #_#?(:clj (:require [cljs-css-modules.macro :as css])))

Adriaan Callaerts08:11:53

(I've tried a few variations where I'm using :include-macros in the cljs-specific bit etc to get the cljs-css-modules.macro ns to load, and then the icon ns and oops.core always need to be loaded)

Adriaan Callaerts08:11:20

The current attempt results in error Feature cannot be (:require [...]) Features must be keywords.

Adriaan Callaerts08:11:03

Which I'm guessing is due to me having two :require's in the ns form, because each seperately doesn't seem to be invalid I think?

Adriaan Callaerts08:11:15

For reference, this seems to be doing better (although I haven't confirmed it functions, at least it's compiling now):

(ns fleet-frontend.fe.components.filter
  #?(:cljs (:refer-clojure :exclude [atom]))
  (:require-macros [cljs-css-modules.macro :as css])
  (:require [oops.core :refer [oget]]
            [fleet-frontend.fe.components.icon :refer [search]]
            #?(:cljs [reagent.core :refer [atom]])))

Adriaan Callaerts08:11:51

Another update: this seems to work for initial compilation, but then when the auto-reload kicks in it throws an error Call to clojure.core/ns did not conform to spec.


Are there any details about the spec error?


Also, just in case - you can avoid having to put :refer-clojure ... :exclude there by creating an alias for ratom or reagent.core namespace as opposed to referring to ratom by name.

Adriaan Callaerts09:11:35

This is all I get:

Compile Exception   src/fleet_frontend/fe/components/filter.cljc   line:1  column:1

  Call to clojure.core/ns did not conform to spec.

  1  (ns fleet-frontend.fe.components.filter
  2    #?(:cljs (:refer-clojure :exclude [atom]))
  3    (:require-macros [cljs-css-modules.macro :refer [defstyle]])
  4    (:require [oops.core :refer [oget]]
  5              [fleet-frontend.fe.components.icon :as icon]
  6              #?(:cljs [reagent.core :refer [atom]])))

Adriaan Callaerts09:11:19

I figured I would have to do the refer [atom] and exclude [atom] to a) in case of clj use the built-in clojure.core/atom and b) in case of cljs use the reagent atom to get a component that at least seems to work in both

Adriaan Callaerts09:11:54

If I just use the reagent ratom in cljc it'll complain in the clojure-side of things because ratom is cljs-only as far as I can tell


The code that uses ratom must also be under a reader conditional.

Adriaan Callaerts09:11:07

but then wouldn't I also have to make every part of the code that derefs the ratom conditional? This was kinda what I am trying to avoid. I'd love to have a cljc component that uses a derefable for internal state. In client-side that would obviously be the ratom, but I don't want to rewrite the entire component for server-side to avoid having the ratom there


Ah, I see.


You can’t have multiple :require statements in your ns expression


You need to put the reader conditionals inside the require

Adriaan Callaerts10:11:09

I tried that, but then I started to get other weird errors from the oops.core dependency, so I decided to dedupe the component into a clj and cljs variant after all. Thanks for the help anyway!

Andrei Stan18:11:45

hi. does reagent has a "native" alternative to dropzonejs ?


Using React component is pretty much as native as it gets: