-
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