Fork me on GitHub
#reagent
<
2018-05-13
>
bupkis17:05:38

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"))))

bupkis17:05:24

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

bupkis17:05:08

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

justinlee17:05:48

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

bupkis17:05:37

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

justinlee17:05:51

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

bupkis17:05:09

thanks, let me try that

bupkis17:05:29

@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

bupkis17:05:04

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

justinlee17:05:57

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

bupkis18:05:27

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

justinlee18:05:28

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

justinlee18:05:57

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

bupkis18:05:18

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

justinlee18:05:33

maybe that’s what draft-js expects

bupkis18:05:11

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

bupkis18:05:59

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

bupkis18:05:34

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

bupkis18:05:27

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.

bupkis18:05:05

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

justinlee20:05:18

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