Fork me on GitHub

Has anyone successfully used the Slate editor component with Reagent/Re-frame? I'm trying to use it, and given the below code it shows, but doesn't react to any events and Chrome just uses up a lot of CPU. Not sure I'm doing it right, as I'm a ClojureScript newbie.

(ns test
  (:require [reagent.core :as r]
            [reagent.interop :refer-macros [$]]
            [re-frame.core :as rf]
            ["slate-react" :refer (Editor)]
            ["slate" :refer (Value)]
            ["slate-plain-serializer" :default Plain]

(defn editor-panel []
  (let [value (r/atom (->> "test initial string"
                           (.deserialize Plain)))]
    [:div {:style {:width 800 :border "1px solid black"}}
     [:> Editor {:value @value
                 :on-change (fn [new-value]
                              (reset! value new-value))}]]))

(defn ^:export ^:dev/after-load init []
  (rf/dispatch-sync [:initialize])
  (r/render [editor-panel]
            (. js/document (getElementById "app"))))


I'm using shadow-cljs, thus the JS string imports in :require


I've had similar lack of success with Draft.js but at least it didn't eat up CPU. So at this point any pointers to use such an editor component would be greatly appreciated


okay one issue is that in editor-panel you need to return a function from inside the let or the component will not re-render on atom update


oh so I need a form-2 component? (not sure if that's the right name)


yes. if you have local atom state, you need form-2


thanks, let me try that


@lee.justin.m thank you, that worked! at least with draft.js. with slate.js I'm getting some other errors about it expecting a slate Value but getting an Object


I guess for now I'll just stick with wrestling draft.js, since at least it appears to do something 🙂


actually i’m pretty sure the error is that you are not setting the correct data in the on-change handler. you are just passing the entire event object instead grabbing the value


you mean I need to change the reset to (reset! value (-> new-value .-target .-value)) or similar?


something like that. i don’t know the slate editor but generally speaking events give you an event object that is a superset of what you want and you need to go looking inside that object for the relevant data


the example i linked to didn’t get the target’s value, it had a value set on the event object. but you can just print the event object to the console and look to see what’s inside


let me try that. but then the weird thing is why then draft-js works after i change it to form-2 and keep that reset. maybe it detects it's an event itself


maybe that’s what draft-js expects


the .-target is nil on that on-change argument


oh got it. (reset! value (.-value new-value)) does the job


now it also works. thank you very much for pointing me in the right direction, @lee.justin.m


For the record, for both slate and draft, I also needed to add a this (r/current-component) in the let and an (r/force-update this) after the reset! in the on-change handler, otherwise they behaved very erratically.


the explanation that I found on the web is that reagent renders on animation frame, and the editors want to be updated as soon as their state changes


Yea that makes sense that you’d need to update state synchronously otherwise you’d have inconsistent events coming in