ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • mhtml - non-reacitve 적용하기
    web/mhtml 2021. 8. 12. 18:46

    monadic html 에서는 reactive functional style 이 기본으로 오히려 non-reactive 하게 만들기가 어려운 것 같다. 그런데 가끔씩 non-reactive 하게 구현할 필요가 있다. submit 버튼을 누를 때 화면 변화가 있도록 만들어 보자.

     

    첫번째 코드

    import mhtml._
    import org.scalajs.dom
    
    import scala.scalajs.js
    import scala.xml.Elem
    
    object MainView {
      case class Info(query: String, deivce: String)
    
      def view() = {
        val submitVar: Var[Unit]   = Var(())
        val queryVar: Var[String]  = Var("")
        val deviceVar: Var[String] = Var("mobile")
    
        def heavyFunction(query: String, device: String): Info = {
          println("heavyFunction called")
          Info(query, device)
        }
    
        val params: Rx[(String, String)] = for {
          q <- queryVar
          d <- deviceVar
        } yield (q, d)
    
        val heavyWork: Rx[Info] = params.sampleOn(submitVar).map {
          case (query, device) => heavyFunction(query, device)
        }
    
        val content: Elem =
          <div style="margin:20px">
            <input type="radio" name="device"  value="mobile" onclick={() => deviceVar := "mobile"}></input>mobile
            <input type="radio" name="device"  value="pc" onclick={() => deviceVar := "pc"}></input>pc
            <br></br>
            <input type="text"  oninput={(e: js.Dynamic) => queryVar := e.target.value.asInstanceOf[String]}></input>
            <button type="button" onclick={() => submitVar := ()}>submit</button>
            <div>device: {heavyWork.map(_.deivce)}</div>
            <div>query: {heavyWork.map(_.query)}</div>
          </div>
        mount(dom.document.getElementById("main_content"), content)
      }
    }

     

    radio 버튼을 선택하고 입력창에 쿼리를 입력후 submit 버튼을 눌렀을 때, 해당 값이 하단에 출력된다.

    mhtml example 처럼 입력창에 쿼리가 한자씩 입력될 때 마다 즉시 하단에 출력되지 않도록 했다!

    이는 sampleOn 을 이용해 submit 버튼이 눌렸을 때만 query 와 device 값을 읽어 화면을 그리도록 했기 때문이다.

        val params: Rx[(String, String)] = for {
          q <- queryVar
          d <- deviceVar
        } yield (q, d)
    
        val heavyWork: Rx[Info] = params.sampleOn(submitVar).map {
          case (query, device) => heavyFunction(query, device)
        }

    그러나 위의 코드에서는 submit 버튼을 누를 때 마다 heavyFunction() 이 두번씩 호출된다는 문제가 있다.

    원인은 아래처럼 heavyWork 의 device, query 를 각각 그리도록 했기 때문이다.

    <div>device: {heavyWork.map(_.deivce)}</div>
    <div>query: {heavyWork.map(_.query)}</div>

    submit 버튼을 누를 때 heavyFunction() 을 한번만 호출해 화면을 그리도록 하려면 어떻게 해야 할까?

    해결 방법은 두번째 코드 처럼 heavyWork 를 전역으로 사용해 Rx[Elem] 의 content 를 만드는 것이다.

     

     

    두번째 코드

    import mhtml._
    import org.scalajs.dom
    
    import scala.scalajs.js
    import scala.xml.Elem
    
    object MainView {
      case class Info(query: String, deivce: String)
    
      def view() = {
        val submitVar: Var[Unit]   = Var(())
        val queryVar: Var[String]  = Var("")
        val deviceVar: Var[String] = Var("mobile")
    
        def heavyFunction(query: String, device: String): Info = {
          println("heavyFunction called")
          Info(query, device)
        }
    
        val params: Rx[(String, String)] = for {
          q <- queryVar
          d <- deviceVar
        } yield (q, d)
    
        val heavyWork: Rx[Info] = params.sampleOn(submitVar).map {
          case (query, device) => heavyFunction(query, device)
        }
    
        val content: Rx[Elem] = heavyWork.map { info =>
          <div style="margin:20px">
            <input type="radio" name="device"  value="mobile" onclick={() => deviceVar := "mobile"}></input>mobile
            <input type="radio" name="device"  value="pc" onclick={() => deviceVar := "pc"}></input>pc
            <br></br>
            <input type="text"  oninput={(e: js.Dynamic) => queryVar := e.target.value.asInstanceOf[String]}></input>
            <button type="button" onclick={() => submitVar := ()}>submit</button>
            <div>device: {info.deivce}</div>
            <div>query: {info.query}</div>
          </div>
        }
    
        mount(dom.document.getElementById("main_content"), content)
      }
    }

    'web > mhtml' 카테고리의 다른 글

    javascript callback 처리 하기 - checkbox  (0) 2021.10.25
    javascript callback 처리 하기 - dropdown  (0) 2021.10.25
    mhtml - Seq[A] 를 화면에 보여주기  (0) 2021.08.12
    mhtml - text input 읽기  (0) 2021.08.12
    mhtml - ajax 호출  (0) 2021.08.11

    댓글

Designed by Tistory.