Search code examples
clojureclojurescriptreagent

How to make inputs change in Reagent?


I'm new to React, Clojure, ClojureScript, and Reagent, so I'm probably missing something simple.

I am modifying code from here (https://reagent-project.github.io) and the default hello-world ClojureScript page to get a simple login page. But whenever I type in something into the username and password fields, nothing happens. Why is this?

(ns cljs_test.core
    (:require [reagent.core :as reagent :refer [atom]]))

(enable-console-print!)

;; define your app data so that it doesn't get over-written on reload

(defonce app-state (atom {:text "Hello world!"}))

; define Reagent component `atom-input`
(defn atom-input [state]
  [:input {:type "text"
    :style {:display "block"}
    :placeholder "Username"
    :value @state
    :on-change (fn [event]
      reset! state (-> event .-target .-value))}])
; define Reagent component `atom-pw`
(defn atom-pw [state]
  [:input {:type "password"
    :style {:display "block"}
    :placeholder "Password"
    :value @state
    :on-change (fn [event]
      reset! state (-> event .-target .-value))}])

Below we invoke the two Reagent components atom-input and atom-pw using the square-bracket "function call".

(defn loginForm [someUrl]
  (let [unVal (atom "") pwVal (atom "")]
    (fn []
      [:div
        [:p "Username: " @unVal]
        [:p "Password: " @pwVal]

        ; Reagent does "magic" here to transform any vector beginning
        ; with a function into a real function call
        [atom-input unVal]             ; line 32
        [atom-pw pwVal]                ; line 33

        [:button "to-do submit button"]])))

(defn app []
  [:div
    [:div
      [:h1 (:text @app-state)]
      [:h3 "Edit this and watch it change!"]]
    [loginForm ""]])

(reagent/render-component [app]
                          (. js/document (getElementById "app")))

(defn on-js-reload []
  ;; optionally touch your app-state to force rerendering depending on
  ;; your application
  ;; (swap! app-state update-in [:__figwheel_counter] inc)
)

Thank you in advance for the responses.


Solution

  • Missing parentheses. Should look like:

    (defn atom-input [state]
      [:input {:type        "text"
               :style       {:display "block"}
               :placeholder "Username"
               :value       @state
               :on-change   (fn [event]
                              (reset! state (-> event .-target .-value)))}])
    

    The parens in Clojure make a function call. Without them, the reset! and the state are ignored. This expression:

    (-> event .-target .-value)
    

    will produce a value, which is then returned by the anonymous function for :on-change. However, this value is ignored.