mentat-collective/JSXGraph.cljs

Convert to function components, hooks, ref on item creation

Closed this issue · 2 comments

We should get refs going for each of the sub-items and also for the big jsxgraph board.

I tried this and found some problems.

If I used this code, then I found that (.removeObject board item) was simply NOT removing items.

(defn JSXGraph*
  "TODO note that you can either add children etc... OR you can supply a ref that
  just does all of this crap for you.

  TODO can I have a component that just messes with the board itself?"
  [{:keys [id style ref] :as props} & children]
  (let [[board set-board] (react/useState nil)
        id (or id (-> (Math/random)
                      (.toString 36)
                      (.substr 2 9)))
        style (or style {:height "400px" :width "100%"})
        kill! (fn [board]
                (when board
                  (js/console.log "bye bye board")
                  (.suspendUpdate board)
                  (-> (.-JSXGraph jsx) (.freeBoard board)))
                nil)
        init! (fn [props]
                (js/console.log (pr-str props))
                (-> (.-JSXGraph jsx)
                    (.initBoard id (clj->js props))))]

    (let [opt-ref (react/useRef props)]
      (when (not= (.-current opt-ref) props)
        (set! (.-current opt-ref) props))

      (react/useEffect
       (fn mount []
         (js/console.log "hi")
         (let [b (init! props)]
           (when ref (ref b))
           (set-board b)
           (fn unmount []
             (kill! b)
             (when ref (ref nil))
             (set-board nil))))
       #js [(.-current opt-ref)]))

    (if-not board
      [:div {:id id :style style}]
      (let [extras {:board board}]
        ;; TODO note that this trick is forcing the children to re-render
        ;; basically every single time. We are using react as a hack here :)
        ;;
        ;; But this means that, for now, you can't be updating this stuff with
        ;; changing properties. You need to use a function that is going to
        ;; access some state. That should be fine!
        (into [:div {:id id :style style}]
              (map
               (fn [[a props & more]]
                 (if (map? props)
                   (into [a (into props extras)] more)
                   (into [a extras props] more))))
              children)))))

(defn JSXGraph2 [& xs]
  (into [:f> JSXGraph*] xs))

Try this:

(cljs
 [jsx/JSXGraph2 {:boundingbox [-5 5 5 -2]
                 :showCopyright false}
  [jsx/Point {:id "C" :size 4 :parents [-3 1]}]
  [jsx/Point {:id "D" :size 4 :parents [-2 1]}]])

comment points out and back in or change params, they don't delete, they DUPLICATE!

Done!