$30 off During Our Annual Pro Sale. View Details »

フロントエンドもKotlinで書きたい! -WebページをKotlin/JSで作った軌跡-

subroh_0508
August 24, 2019

フロントエンドもKotlinで書きたい! -WebページをKotlin/JSで作った軌跡-

Kotlin Fest 2019 - Hall C 16:45〜
「フロントエンドもKotlinで書きたい! -WebページをKotlin/JSで作った軌跡-」のセッション資料です

subroh_0508

August 24, 2019
Tweet

More Decks by subroh_0508

Other Decks in Technology

Transcript

  1. "CPVU.F w ʹ͜͠Γ͞ͿΖʙ ຊ໊ࡔ্੖৴  w ౦ژ౎ɾҏ౾େౡग़਎ w גࣜձࣾ#FBS5BJM w

    "OESPJEΤϯδχΞ ,PUMJO+BWB ˑ w 8FCΤϯδχΞ 3BJMT3FBDU  w झຯͰ,PUMJO+4
  2. ,PUMJO+4ͷ֓ཁ +4ͰͷϑϩϯτΤϯυ։ൃʹඞཁͳϞϊ w +4ίʔυɾελΠϧγʔτ $44 ɾ)5.-ϑΝΠϧ w ύοέʔδ؅ཧπʔϧ OQN 

    w Ϟδϡʔϧόϯυϥʔ 8FCQBDL  w ෳ਺ͷ+4ϞδϡʔϧΛͭʹ·ͱΊɺ)5.-Ͱѻ͍΍͍͢ܗʹ͢Δ w Ϟδϡʔϧؒͷґଘؔ܎ղܾɺNJOJGZɺίʔυɾϦιʔεͷม׵ ྫ54ˠ+4ɺ4BTTˠ$44
  3. ,PUMJO+4ͷ֓ཁ w +4ίʔυʹม׵Մೳͳ,PUMJOඪ४ϥΠϒϥϦ w ,PUMJOˠ+4΁ͷม׵Λ࣮ߦ͢Δ(SBEMFϓϥάΠϯ w OQN8FCQBDLͷίϚϯυΛ࣮ߦ͢Δ(SBEMFϓϥάΠϯ ʴIUNMDTTͷ%4-ϥΠϒϥϦɺ֤छ+4 ϥούʔ ϥΠϒϥϦ

    ,PUMJO+4͕ఏڙ͢ΔϞϊ ,PUMJO͔Β+4΁ͷม׵ɺOQNʹΑΔόʔδϣϯ؅ཧɺ8FCQBDLʹΑΔόϯυϧ શͯΛ,PUMJOͷੈքͰ׬݁ͤ͞ɺϑϩϯτΤϯυ։ൃΛ࣮ݱ͢Δʂ
  4. ,PUMJO+4ͷྺ࢙ ,PUMJOϦϦʔε w ,PUMJO+4ਖ਼ࣜϦϦʔεɻʮLPUMJOKTʯͰ,PUMJOˠ+4ม׵͕Ͱ͖ΔΑ͏ʹ LPUMJOGSPOUFOEQMVHJOϦϦʔε w (SBEMF͔ΒͷOQNɺ8FCQBDLͷίϚϯυ࣮ߦΛαϙʔτ͢ΔϓϥάΠϯ ,PUMJOϦϦʔε w ,PUMJO.11ొ৔ɻ+7.΍/BUJWFͷϞδϡʔϧͱϩδοΫΛڞ௨Խ

    ,PUMJOϦϦʔε w LPUMJOKTˠDPNKFUCSBJOTLPUMJOKTʹվ໊ɺLPUMJOGSPOUFOEQMVHJOͷҰ෦ػೳ͕౷߹ w ʮLPUMJOGSPOUFOEQMVHJO͸ࠓޙഇࢭ༧ఆʯͱࠂ஌ ,PUMJOϦϦʔε w 8FCQBDLͷઃఆ߲໨௥Ճɺόάमਖ਼
  5. ,PUMJOϦϦʔε w ,PUMJO+4ਖ਼ࣜϦϦʔεɻʮLPUMJOKTʯͰ,PUMJOˠ+4ม׵͕Ͱ͖ΔΑ͏ʹ LPUMJOGSPOUFOEQMVHJOϦϦʔε w (SBEMF͔ΒͷOQNɺ8FCQBDLͷίϚϯυ࣮ߦΛαϙʔτ͢ΔϓϥάΠϯ ,PUMJOϦϦʔε w ,PUMJO.11ొ৔ɻ+7.΍/BUJWFͷϞδϡʔϧͱϩδοΫΛڞ௨Խ ,PUMJOϦϦʔε

    w LPUMJOKTˠDPNKFUCSBJOTLPUMJOKTʹվ໊ɺLPUMJOGSPOUFOEQMVHJOͷҰ෦ػೳ͕౷߹ w ʮLPUMJOGSPOUFOEQMVHJO͸ࠓޙഇࢭ༧ఆʯͱࠂ஌ ,PUMJOϦϦʔε w 8FCQBDLͷઃఆ߲໨௥Ճɺόάमਖ਼ ,PUMJO+4ͷྺ࢙ ,PUMJO.11ͷҰ෦ͱͯ͠ ֤छϓϥάΠϯ͕·ͱ·ΔྲྀΕ
  6. ,PUMJOϦϦʔε w ,PUMJO+4ਖ਼ࣜϦϦʔεɻʮLPUMJOKTʯͰ,PUMJOˠ+4ม׵͕Ͱ͖ΔΑ͏ʹ LPUMJOGSPOUFOEQMVHJOϦϦʔε w (SBEMF͔ΒͷOQNɺ8FCQBDLͷίϚϯυ࣮ߦΛαϙʔτ͢ΔϓϥάΠϯ ,PUMJOϦϦʔε w ,PUMJO.11ొ৔ɻ+7.΍/BUJWFͷϞδϡʔϧͱϩδοΫΛڞ௨Խ ,PUMJOϦϦʔε

    w LPUMJOKTˠDPNKFUCSBJOTLPUMJOKTʹվ໊ɺLPUMJOGSPOUFOEQMVHJOͷҰ෦ػೳ͕౷߹ w ʮLPUMJOGSPOUFOEQMVHJO͸ࠓޙഇࢭ༧ఆʯͱࠂ஌ ,PUMJOϦϦʔε w 8FCQBDLͷઃఆ߲໨௥Ճɺόάमਖ਼ ,PUMJO+4ͷྺ࢙ ͜ͷ࣌ظͷ৘ใ͕݁ߏଟ͍ ࠓޙݹ͘ͳΔͷͰ஫ҙʂ
  7. ࣄྫ  ϙʔτϑΥϦΦαΠτ (JUIVCTVCSPIQPSUGPMJP ࢖༻ϥΠϒϥϦɾ"1* w ,PUMJO+4 W  w

    3FBDUKT w .BUFSJBM6* ˠ'JSFCBTF)PTUJOHͰϗεςΟϯά ɹ-JOLTVCSPINF w (PPHMF.BQ"1* w SFBDUTXJQFBCMFWJFXT
  8. ࣄྫ  খௗ͞Μͷࣗशࣨ (JUIVCTVCSPIPUPOBTIJLPUMJOEFW ࢓༷ϥΠϒϥϦ w ,PUMJO+4 W  w

    3FBDUKT w .BUFSJBM6* ˠϧʔςΟϯάϥΠϒϥϦΛ࢖ͬͨ41" ɹ খௗ͞Μ w 3FBDI3PVUFS w LPUMJOQMBZHSPVOE
  9.  ,PUMJO+4 OQN w ϞδϡʔϧͷΠϯετʔϧɾϓϩδΣΫτੜ੒ɾ࣮ߦ # インストール $ npm install

    -g create-react-kotlin-app # プロジェクト生成 $ create-react-kotlin-app my-app # 実行 $ cd my-app/ $ npm start
  10. ,PUMJO+4ͷϥούʔϞδϡʔϧ͕ ґଘؔ܎ʹ௥ՃࡁΈʂ "devDependencies": { "@jetbrains/gen-idea-libs": "^1.0.11", "@jetbrains/kotlin-extensions": "^1.0.1-pre.58", "@jetbrains/kotlin-react": "^16.5.2-pre.58",

    "@jetbrains/kotlin-react-dom": "^16.5.2-pre.58", "@jetbrains/kotlin-webpack-plugin": "^2.0.3", "@jetbrains/ts2kt-automator": "^1.0.12", "kotlin": "^1.3.0", "kotlinx-html": “^0.6.11", … }
  11. package index import … fun main(args: Array<String>) { requireAll(require.context("src", true,

    js("/\\.css$/"))) render(document.getElementById("root")) { child(App::class) { } } }
  12. package index import … fun main(args: Array<String>) { requireAll(require.context("src", true,

    js("/\\.css$/"))) render(document.getElementById("root")) { child(App::class) { } } } TSDҎԼͷDTTΛҰׅಡΈࠐΈ
  13. package index import … fun main(args: Array<String>) { requireAll(require.context("src", true,

    js("/\\.css$/"))) render(document.getElementById("root")) { child(App::class) { } } } "QQίϯϙʔωϯτΛSFOEFS
  14. package app import … class App : RComponent<RProps, RState>() {

    override fun RBuilder.render() { div("App-header") { child(Logo::class) { } h2 { +"Welcome to React with Kotlin" } } p("App-intro") { +"To get started, edit " code { +"app/App.kt" } +" and save to reload." } p("App-ticker") { child(Ticker:class) { attrs.startFrom = 0 } } } }
  15. package app import … class App : RComponent<RProps, RState>() {

    override fun RBuilder.render() { div("App-header") { child(Logo::class) { } h2 { +"Welcome to React with Kotlin" } } p("App-intro") { +"To get started, edit " code { +"app/App.kt" } +" and save to reload." } p("App-ticker") { child(Ticker:class) { attrs.startFrom = 0 } } } } 3$PNQPOFOUΛܧঝ$PNQPOFOUఆٛ
  16. package app import … class App : RComponent<RProps, RState>() {

    override fun RBuilder.render() { div("App-header") { child(Logo::class) { } h2 { +"Welcome to React with Kotlin" } } p("App-intro") { +"To get started, edit " code { +"app/App.kt" } +" and save to reload." } p("App-ticker") { child(Ticker:class) { attrs.startFrom = 0 } } } } SFOEFSϝιου಺ʹIUNMΛ%4-Ͱهड़
  17. package app import … class App : RComponent<RProps, RState>() {

    override fun RBuilder.render() { div("App-header") { child(Logo::class) { } h2 { +"Welcome to React with Kotlin" } } p("App-intro") { +"To get started, edit " code { +"app/App.kt" } +" and save to reload." } p("App-ticker") { child(Ticker:class) { attrs.startFrom = 0 } } } } EJWDMBTT/BNFl"QQIFBEFSzʜEJW
  18. package app import … class App : RComponent<RProps, RState>() {

    override fun RBuilder.render() { div("App-header") { child(Logo::class) { } h2 { +"Welcome to React with Kotlin" } } p("App-intro") { +"To get started, edit " code { +"app/App.kt" } +" and save to reload." } p("App-ticker") { child(Ticker:class) { attrs.startFrom = 0 } } } } I8FMDPNFUP3FBDUXJUI,PUMJOI
  19. package app import … class App : RComponent<RProps, RState>() {

    override fun RBuilder.render() { div("App-header") { child(Logo::class) { } h2 { +"Welcome to React with Kotlin" } } p("App-intro") { +"To get started, edit " code { +"app/App.kt" } +" and save to reload." } p("App-ticker") { child(Ticker:class) { attrs.startFrom = 0 } } } } ճస͢Δϩΰͷදࣔίϯϙʔωϯτ
  20. package app import … class App : RComponent<RProps, RState>() {

    override fun RBuilder.render() { div("App-header") { child(Logo::class) { } h2 { +"Welcome to React with Kotlin" } } p("App-intro") { +"To get started, edit " code { +"app/App.kt" } +" and save to reload." } p("App-ticker") { child(Ticker:class) { attrs.startFrom = 0 } } } } ܦա࣌ؒදࣔͷίϯϙʔωϯτ
  21. interface TickerProps : RProps { var startFrom: Int } interface

    TickerState : RState { var secondsElapsed: Int } class Ticker(props: TickerProps) : RComponent<TickerProps, TickerState>(props) { override fun TickerState.init(props: TickerProps) { secondsElapsed = props.startFrom } var timerID: Int? = null override fun componentDidMount() { timerID = window.setInterval({ setState { secondsElapsed += 1 } }, 1000) } override fun componentWillUnmount() { window.clearInterval(timerID!!) } override fun RBuilder.render() { +"This app has been running for ${state.secondsElapsed} seconds." } }
  22. interface TickerProps : RProps { var startFrom: Int } interface

    TickerState : RState { var secondsElapsed: Int } class Ticker(props: TickerProps) : RComponent<TickerProps, TickerState>(props) { override fun TickerState.init(props: TickerProps) { secondsElapsed = props.startFrom } var timerID: Int? = null override fun componentDidMount() { timerID = window.setInterval({ setState { secondsElapsed += 1 } }, 1000) } override fun componentWillUnmount() { window.clearInterval(timerID!!) } override fun RBuilder.render() { +"This app has been running for ${state.secondsElapsed} seconds." } } 31SPQTΛܧঝͨ͠5JDLFS1SPQT ˠ਌ίϯϙʔωϯτ͔Β ɹड͚औΔ஋ͷఆٛ
  23. interface TickerProps : RProps { var startFrom: Int } interface

    TickerState : RState { var secondsElapsed: Int } class Ticker(props: TickerProps) : RComponent<TickerProps, TickerState>(props) { override fun TickerState.init(props: TickerProps) { secondsElapsed = props.startFrom } var timerID: Int? = null override fun componentDidMount() { timerID = window.setInterval({ setState { secondsElapsed += 1 } }, 1000) } override fun componentWillUnmount() { window.clearInterval(timerID!!) } override fun RBuilder.render() { +"This app has been running for ${state.secondsElapsed} seconds." } } 34UBUFΛܧঝͨ͠5JDLFS4UBUF ˠ5JDLFSίϯϙʔωϯτͷঢ়ଶ
  24. interface TickerProps : RProps { var startFrom: Int } interface

    TickerState : RState { var secondsElapsed: Int } class Ticker(props: TickerProps) : RComponent<TickerProps, TickerState>(props) { override fun TickerState.init(props: TickerProps) { secondsElapsed = props.startFrom } var timerID: Int? = null override fun componentDidMount() { timerID = window.setInterval({ setState { secondsElapsed += 1 } }, 1000) } override fun componentWillUnmount() { window.clearInterval(timerID!!) } override fun RBuilder.render() { +"This app has been running for ${state.secondsElapsed} seconds." } } JOJUؔ਺Ͱܦա࣌ؒͷॳظԽ
  25. interface TickerProps : RProps { var startFrom: Int } interface

    TickerState : RState { var secondsElapsed: Int } class Ticker(props: TickerProps) : RComponent<TickerProps, TickerState>(props) { override fun TickerState.init(props: TickerProps) { secondsElapsed = props.startFrom } var timerID: Int? = null override fun componentDidMount() { timerID = window.setInterval({ setState { secondsElapsed += 1 } }, 1000) } override fun componentWillUnmount() { window.clearInterval(timerID!!) } override fun RBuilder.render() { +"This app has been running for ${state.secondsElapsed} seconds." } } ඵ͝ͱʹTUBUFͷ஋Λߋ৽ ˞TFU4UBUFϝιουͰ஋ߋ৽ SFOEFSϝιουͷݺͼग़͠
  26. interface TickerProps : RProps { var startFrom: Int } interface

    TickerState : RState { var secondsElapsed: Int } class Ticker(props: TickerProps) : RComponent<TickerProps, TickerState>(props) { override fun TickerState.init(props: TickerProps) { secondsElapsed = props.startFrom } var timerID: Int? = null override fun componentDidMount() { timerID = window.setInterval({ setState { secondsElapsed += 1 } }, 1000) } override fun componentWillUnmount() { window.clearInterval(timerID!!) } override fun RBuilder.render() { +"This app has been running for ${state.secondsElapsed} seconds." } } ܦա࣌ؒͷදࣔ
  27. ίʔυൺֱ class App extends React.Component { render() { return (

    <div className='App-header'> <Logo/> <h2>Welcome to React with Kotlin</h2> <p className='App-intro'> To get started, edit <code>app/App.kt</code> and save to reload. </p> <p className='App-ticker'> <Ticker startFrom={ 0 }/> </p> </div> ); } } class App : RComponent<RProps, RState>() { override fun RBuilder.render() { div("App-header") { child(Logo::class) { } h2 { +"Welcome to React with Kotlin" } } p("App-intro") { +"To get started, edit " code { +"app/App.kt" } +" and save to reload." } p("App-ticker") { child(Ticker:class) { attrs.startFrom = 0 } } } } +4 ,PUMJO
  28. w +4ϥΠϒϥϦΛ௥Ճ͍ͨ͠ʂ w npm install hoge --save w ௥Ճͨ͠+4ϥΠϒϥϦΛ,PUMJOͰѻ͍͍ͨʂ w

    ޙड़ w 8FCQBDLͷઃఆΛΧελϚΠζ͍ͨ͠ʂ w npm run eject ͰઃఆϑΝΠϧΛग़ྗՄ  ,PUMJO+4 OQN
  29. (SBEMF1MVHJOͷࢦఆ SFQPTJUPSJFTͷࢦఆ  ,PUMJO+4 (SBEMF plugins { id 'org.jetbrains.kotlin.js' version

    '1.3.50' } group 'subroh0508.net' version '1.0-SNAPSHOT' repositories { jcenter() mavenCentral() maven { url "http://dl.bintray.com/kotlin/kotlin-js-wrappers" } maven { url 'https://plugins.gradle.org/m2/' } }
  30. 8FCQBDLͷઃఆ  ,PUMJO+4 (SBEMF kotlin { target { browser {

    runTask { devServer = new KotlinWebpackConfig.DevServer( true, false, true, true, false, 8080, null, ["$projectDir/src/main/resources".toString()] ) archiveFileName = "kotlin-react-sample.js" } } }
  31. 8FCQBDLͷઃఆ  ,PUMJO+4 (SBEMF kotlin { target { browser {

    runTask { devServer = new KotlinWebpackConfig.DevServer( true, false, true, true, false, 8080, null, ["$projectDir/src/main/resources".toString()] ) archiveFileName = "kotlin-react-sample.js" } } } CSPXTFSϒϩοΫ಺Ͱ 8FCQBDLͷઃఆΛهड़
  32. kotlin { target { browser { runTask { devServer =

    new KotlinWebpackConfig.DevServer( true, false, true, true, false, 8080, null, ["$projectDir/src/main/resources".toString()] ) archiveFileName = "kotlin-react-sample.js" } } } 8FCQBDLͷઃఆ  ,PUMJO+4 (SBEMF QPSUɾQSPYZɾDPOUFOU#BTF౳Λࢦఆ ˠϦιʔεσΟϨΫτϦͷύεΛ DPOUFOU#BTFʹࢦఆ
  33. kotlin { target { browser { runTask { devServer =

    new KotlinWebpackConfig.DevServer( true, false, true, true, false, 8080, null, ["$projectDir/src/main/resources".toString()] ) archiveFileName = "kotlin-react-sample.js" } } } 8FCQBDLͷઃఆ  ,PUMJO+4 (SBEMF BSDIJWF'JMF/BNF ˠόϯυϧޙͷϑΝΠϧ໊
  34. ϥΠϒϥϦͷґଘؔ܎  ,PUMJO+4 (SBEMF sourceSets { main { dependencies {

    implementation "org.jetbrains.kotlin:kotlin-stdlib-js" implementation "org.jetbrains.kotlinx:kotlinx-html-js:0.6.12" implementation "org.jetbrains:kotlin-react:16.9.0-pre.83-kotlin-1.3.41" implementation "org.jetbrains:kotlin-react-dom:16.9.0-pre.83-kotlin-1.3.41" implementation "org.jetbrains:kotlin-styled:1.0.0-pre.83-kotlin-1.3.41" implementation npm("core-js", "~3.1.4") implementation npm("react", "16.9.0") implementation npm("react-dom", "16.9.0") implementation npm("styled-components", "3.4.10") implementation npm("inline-style-prefixer", "5.0.4") } } }
  35. sourceSets { main { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-js" implementation "org.jetbrains.kotlinx:kotlinx-html-js:0.6.12"

    implementation "org.jetbrains:kotlin-react:16.9.0-pre.83-kotlin-1.3.41" implementation "org.jetbrains:kotlin-react-dom:16.9.0-pre.83-kotlin-1.3.41" implementation "org.jetbrains:kotlin-styled:1.0.0-pre.83-kotlin-1.3.41" implementation npm("core-js", "~3.1.4") implementation npm("react", "16.9.0") implementation npm("react-dom", "16.9.0") implementation npm("styled-components", "3.4.10") implementation npm("inline-style-prefixer", "5.0.4") } } } ϥΠϒϥϦͷґଘؔ܎  ,PUMJO+4 (SBEMF ,PUMJO+4ͷඪ४ϥΠϒϥϦ
  36. ϥΠϒϥϦͷґଘؔ܎ sourceSets { main { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-js" implementation

    "org.jetbrains.kotlinx:kotlinx-html-js:0.6.12" implementation "org.jetbrains:kotlin-react:16.9.0-pre.83-kotlin-1.3.41" implementation "org.jetbrains:kotlin-react-dom:16.9.0-pre.83-kotlin-1.3.41" implementation "org.jetbrains:kotlin-styled:1.0.0-pre.83-kotlin-1.3.41" implementation npm("core-js", "~3.1.4") implementation npm("react", "16.9.0") implementation npm("react-dom", "16.9.0") implementation npm("styled-components", "3.4.10") implementation npm("inline-style-prefixer", "5.0.4") } } }  ,PUMJO+4 (SBEMF LPUMJOYIUNMIUNMͷ%4-ϥΠϒϥϦ LPUMJOSFBDU3FBDUͷϥούʔϥΠϒϥϦ
  37. sourceSets { main { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-js" implementation "org.jetbrains.kotlinx:kotlinx-html-js:0.6.12"

    implementation "org.jetbrains:kotlin-react:16.9.0-pre.83-kotlin-1.3.41" implementation "org.jetbrains:kotlin-react-dom:16.9.0-pre.83-kotlin-1.3.41" implementation "org.jetbrains:kotlin-styled:1.0.0-pre.83-kotlin-1.3.41" implementation npm("core-js", "~3.1.4") implementation npm("react", "16.9.0") implementation npm("react-dom", "16.9.0") implementation npm("styled-components", "3.4.10") implementation npm("inline-style-prefixer", "5.0.4") } } } ϥΠϒϥϦͷґଘؔ܎  ,PUMJO+4 (SBEMF +4ͷϥΠϒϥϦ͸OQN  Ͱࢦఆ
  38. ,PUMJO+4ͷίʔσΟϯά  ,PUMJO+4 (SBEMF // main.kt fun main() { render(document.getElementById("root"))

    { child(App::class) { } } } // App.kt class App : RComponent<RProps, RState>() { override fun RBuilder.render() { div { +"Hello, World!" } } }
  39. JOEFYIUNMͷ࡞੒  ,PUMJO+4 (SBEMF <!DOCTYPE html> <html lang="en"> <head> <meta

    charset="UTF-8"> <title>Title</title> </head> <body> <div id="root"></div> <script src="kotlin-react-sample.js"></script> </body> </html> ˡIUNMϑΝΠϧΛ SFTPVSDFTҎԼʹ഑ஔ
  40. ಈ͖Λ͚͍ͭͨ ྫΧ΢ϯλʔ interface AppState : RState { var count: Int

    } class App : RComponent<RProps, AppState>() { override fun AppState.init() { count = 0 } private fun onClickedButton() { setState { count += 1 } } override fun RBuilder.render() { div { +"count: ${state.count}" } button { attrs.onClickFunction = { onClickedButton() } +"click!" } } }
  41. interface AppState : RState { var count: Int } class

    App : RComponent<RProps, AppState>() { override fun AppState.init() { count = 0 } private fun onClickedButton() { setState { count += 1 } } override fun RBuilder.render() { div { +"count: ${state.count}" } button { attrs.onClickFunction = { onClickedButton() } +"click!" } } } TUBUFͷܕఆٛ ಈ͖Λ͚͍ͭͨ ྫΧ΢ϯλʔ
  42. interface AppState : RState { var count: Int } class

    App : RComponent<RProps, AppState>() { override fun AppState.init() { count = 0 } private fun onClickedButton() { setState { count += 1 } } override fun RBuilder.render() { div { +"count: ${state.count}" } button { attrs.onClickFunction = { onClickedButton() } +"click!" } } } TUBUFͷॳظԽ ಈ͖Λ͚͍ͭͨ ྫΧ΢ϯλʔ
  43. interface AppState : RState { var count: Int } class

    App : RComponent<RProps, AppState>() { override fun AppState.init() { count = 0 } private fun onClickedButton() { setState { count += 1 } } override fun RBuilder.render() { div { +"count: ${state.count}" } button { attrs.onClickFunction = { onClickedButton() } +"click!" } } } ϘλϯΫϦοΫ࣌ͷίʔϧόοΫؔ਺ ˠTFU4UBUFϝιουͰΧ΢ϯτΛ૿΍͢ ಈ͖Λ͚͍ͭͨ ྫΧ΢ϯλʔ
  44. interface AppState : RState { var count: Int } class

    App : RComponent<RProps, AppState>() { override fun AppState.init() { count = 0 } private fun onClickedButton() { setState { count += 1 } } override fun RBuilder.render() { div { +"count: ${state.count}" } button { attrs.onClickFunction = { onClickedButton() } +"click!" } } } Χ΢ϯτͷදࣔͱίʔϧόοΫͷࢦఆ ˠBUUSTPO$MJDL'VODUJPO\^ ಈ͖Λ͚͍ͭͨ ྫΧ΢ϯλʔ
  45. ελΠϧΛ͚͍ͭͨ DTTJO,PUMJO override fun RBuilder.render() { div { +"count: ${state.count}"

    } styledButton { css { width = 200.px height = 100.px backgroundColor = Color.aqua } attrs.onClickFunction = { onClickedButton() } +"click!" } }
  46. ελΠϧΛ͚͍ͭͨ DTTJO,PUMJO override fun RBuilder.render() { div { +"count: ${state.count}"

    } styledButton { css { width = 200.px height = 100.px backgroundColor = Color.aqua } attrs.onClickFunction = { onClickedButton() } +"click!" } } TUZMFE#VUUPOʹ͢Δͱ DTT IBOEMFS3VMF4FU ϝιου͕ੜ͑Δ
  47. ελΠϧΛ͚͍ͭͨ DTTJO,PUMJO override fun RBuilder.render() { div { +"count: ${state.count}"

    } styledButton { css { width = 200.px height = 100.px backgroundColor = Color.aqua } attrs.onClickFunction = { onClickedButton() } +"click!" } } DTTϒϩοΫͷதͰελΠϧΛهड़ ˞TUZMFEDPNQPOFOUͷػೳ
  48. +4੡ϥΠϒϥϦͷಋೖ ґଘؔ܎௥Ճ ྫSFBDUTXJQFBCMFWJFXT  w OQNͷ৔߹ npm install react-swipeable-views --save

    w (SBEMFͷ৔߹CVJMEHSBEMFʹ௥ه sourceSets { main { dependencies { ... implementation npm("react-swipeable-views") ... } } }
  49. +4੡ϥΠϒϥϦͷಋೖ !+T.PEVMFΞϊςʔγϣϯ w +4ϥΠϒϥϦΛ,PUMJOͷੈքʹΠϯϙʔτ͢ΔΞϊςʔγϣϯ @JsModule("react-swipeable-views") private external val reactSwipeableViewModule: dynamic

    fun test() { reactSwipeableViewModule.default.onChangeIndex = { ... } } +4ϥΠϒϥϦΛΠϯϙʔτ PO$IBOHF*OEFYʹ ϥϜμࣜΛ୅ೖ Ξϊςʔγϣϯ͚ͭͩʂ +4੡ϥΠϒϥϦΛ,PUMJOͷੈքͰ ҰԠ͸ ѻ͑Δʂ
  50. +4੡ϥΠϒϥϦͷಋೖ EZOBNJDܕ w ,PUMJOͱ+4ͷڮ౉͠Λ୲͏ܕ w ,PUMJOͷੈքͰ+4ͷΦϒδΣΫτΛͦͷ··දݱ͢Δ͜ͱ͕Ͱ͖Δ // { foo: 'foo',

    bar: { hoge: 111 } }をKotlinで扱う場合 val jsObject: dynamic = js("{ foo: 'foo', bar: { hoge: 111 } }") print(jsObject["foo"]) // => 'foo' print(jsObject["bar"]["hoge"]) // => 111 jsObject["aaa"]["bbb"] = "add from kotlin" print(jsObject["aaa"]["bbb"]) // => add from kotlin
  51. +4੡ϥΠϒϥϦͷಋೖ EZOBNJDܕ w ,PUMJOͱ+4ͷڮ౉͠Λ୲͏ܕ w ,PUMJOͷੈքͰ+4ͷΦϒδΣΫτΛͦͷ··දݱ͢Δ͜ͱ͕Ͱ͖Δ // { foo: 'foo',

    bar: { hoge: 111 } }をKotlinで扱う場合 val jsObject: dynamic = js("{ foo: 'foo', bar: { hoge: 111 } }") print(jsObject["foo"]) // => 'foo' print(jsObject["bar"]["hoge"]) // => 111 jsObject["aaa"]["bbb"] = "add from kotlin" print(jsObject["aaa"]["bbb"]) // => add from kotlin +4ͷΦϒδΣΫτΛੜ੒
  52. +4੡ϥΠϒϥϦͷಋೖ EZOBNJDܕ w ,PUMJOͱ+4ͷڮ౉͠Λ୲͏ܕ w ,PUMJOͷੈքͰ+4ͷΦϒδΣΫτΛͦͷ··දݱ͢Δ͜ͱ͕Ͱ͖Δ // { foo: 'foo',

    bar: { hoge: 111 } }をKotlinで扱う場合 val jsObject: dynamic = js("{ foo: 'foo', bar: { hoge: 111 } }") print(jsObject["foo"]) // => 'foo' print(jsObject["bar"]["hoge"]) // => 111 jsObject["aaa"]["bbb"] = "add from kotlin" print(jsObject["aaa"]["bbb"]) // => add from kotlin ଘࡏ͢ΔΩʔͷ஋Λऔͬͯ͘Δ
  53. +4੡ϥΠϒϥϦͷಋೖ EZOBNJDܕ w ,PUMJOͱ+4ͷڮ౉͠Λ୲͏ܕ w ,PUMJOͷੈքͰ+4ͷΦϒδΣΫτΛͦͷ··දݱ͢Δ͜ͱ͕Ͱ͖Δ // { foo: 'foo',

    bar: { hoge: 111 } }をKotlinで扱う場合 val jsObject: dynamic = js("{ foo: 'foo', bar: { hoge: 111 } }") print(jsObject["foo"]) // => 'foo' print(jsObject["bar"]["hoge"]) // => 111 jsObject["aaa"]["bbb"] = "add from kotlin" print(jsObject["aaa"]["bbb"]) // => add from kotlin ଘࡏ͠ͳ͍Ωʔͷ஋Λ +4ʹ͍ۙจ๏Ͱ୅ೖͰ͖ͯ͠·͏
  54. +4੡ϥΠϒϥϦͷಋೖ EZOBNJDܕ w ,PUMJOͱ+4ͷڮ౉͠Λ୲͏ܕ w ,PUMJOͷੈքͰ+4ͷΦϒδΣΫτΛͦͷ··දݱ͢Δ͜ͱ͕Ͱ͖Δ // { foo: 'foo',

    bar: { hoge: 111 } }をKotlinで扱う場合 val jsObject: dynamic = js("{ foo: 'foo', bar: { hoge: 111 } }") print(jsObject.foo) // => 'foo' print(jsObject.bar.hoge) // => 111 jsObject.aaa.bbb = "add from kotlin" // => Error! ͜͏ͳͬͯཉ͍͠
  55. FYUFSOBMम০ࢠ w ,PUMJOͷܕఆٛͱ+4ͷΦϒδΣΫτΛϚοϐϯά͢Δम০ࢠ external interface TestObject { var foo: String

    var bar: TestChildObject } external interface TestChildObject { var hoge: String } val jsObject: TestObject = js("{ foo: 'foo', bar: { hoge: '111' } }") print(jsObject.foo) // => 'foo' print(jsObject.bar.hoge) // => 111 5ZQF4DSJQUͷܕఆٛϑΝΠϧͱ ໾ׂ͸ಉ͡ +4੡ϥΠϒϥϦͷಋೖ
  56. +4੡ϥΠϒϥϦΛʮ,PUMJOΒ͘͠ʯѻ͏ʹ͸ w FYUFSOBMम০ࢠΛ͚ͭͨΠϯλʔϑΣʔεͰܕఆٛ w +4ͷؔ਺Λ,PUMJOΒ͘͠ݺ΂ΔΑ͏ʹؔ਺ఆٛ +4੡ϥΠϒϥϦͷಋೖ @JsModule("react-swipeable-views") private external val

    reactSwipeableViewModule: dynamic external interface ReactSwipeableProps : RProps { var onChangeIndex: (Int, Int, ChangeReason) -> Unit } val RBuilder.swipeableViews: RClass<ReactSwipeableProps> get() = reactSwipeableViewModule.default as RClass<ReactSwipeableProps>
  57. +4੡ϥΠϒϥϦΛʮ,PUMJOΒ͘͠ʯѻ͏ʹ͸ w FYUFSOBMम০ࢠΛ͚ͭͨΠϯλʔϑΣʔεͰܕఆٛ w +4ͷؔ਺Λ,PUMJOΒ͘͠ݺ΂ΔΑ͏ʹؔ਺ఆٛ +4੡ϥΠϒϥϦͷಋೖ @JsModule("react-swipeable-views") private external val

    reactSwipeableViewModule: dynamic external interface ReactSwipeableProps : RProps { var onChangeIndex: (Int, Int, ChangeReason) -> Unit } val RBuilder.swipeableViews: RClass<ReactSwipeableProps> get() = reactSwipeableViewModule.default as RClass<ReactSwipeableProps> FYUFSOBMJOUFSGBDFΛఆٛ ˠϓϩύςΟʮPO$IBOHF*OEFYʯ͕ ɹଘࡏ͢Δ͜ͱΛڭ͑ࠐ·ͤΔ
  58. +4੡ϥΠϒϥϦΛʮ,PUMJOΒ͘͠ʯѻ͏ʹ͸ w FYUFSOBMम০ࢠΛ͚ͭͨΠϯλʔϑΣʔεͰܕఆٛ w +4ͷؔ਺Λ,PUMJOΒ͘͠ݺ΂ΔΑ͏ʹؔ਺ఆٛ +4੡ϥΠϒϥϦͷಋೖ @JsModule("react-swipeable-views") private external val

    reactSwipeableViewModule: dynamic external interface ReactSwipeableProps : RProps { var onChangeIndex: (Int, Int, ChangeReason) -> Unit } val RBuilder.swipeableViews: RClass<ReactSwipeableProps> get() = reactSwipeableViewModule.default as RClass<ReactSwipeableProps> Πϯϙʔτͨ͠ϞδϡʔϧΛ3$MBTT31SPQTʹΩϟετ
  59. +4੡ϥΠϒϥϦΛʮ,PUMJOΒ͘͠ʯѻ͏ʹ͸ w FYUFSOBMम০ࢠΛ͚ͭͨΠϯλʔϑΣʔεͰܕఆٛ w +4ͷؔ਺Λ,PUMJOΒ͘͠ݺ΂ΔΑ͏ʹؔ਺ఆٛ +4੡ϥΠϒϥϦͷಋೖ fun ReactSwipeableProps.onChangeIndex(block: (Int) ->

    Unit) { onChangeIndex = { index: Int, _, _ -> block(index) } } // RComponentクラス内 override fun RBuilder.render() { swipeableViews { attrs.onChangeIndex { i -> setState { tabNumber = i } } } }
  60. +4੡ϥΠϒϥϦΛʮ,PUMJOΒ͘͠ʯѻ͏ʹ͸ w FYUFSOBMम০ࢠΛ͚ͭͨΠϯλʔϑΣʔεͰܕఆٛ w +4ͷؔ਺Λ,PUMJOΒ͘͠ݺ΂ΔΑ͏ʹؔ਺ఆٛ +4੡ϥΠϒϥϦͷಋೖ fun ReactSwipeableProps.onChangeIndex(block: (Int) ->

    Unit) { onChangeIndex = { index: Int, _, _ -> block(index) } } // RComponentクラス内 override fun RBuilder.render() { swipeableViews { attrs.onChangeIndex { i -> setState { tabNumber = i } } } } 1SPQTͷ֦ுؔ਺ͱͯ͠ ηολʔΛఆٛ
  61. +4੡ϥΠϒϥϦΛʮ,PUMJOΒ͘͠ʯѻ͏ʹ͸ w FYUFSOBMम০ࢠΛ͚ͭͨΠϯλʔϑΣʔεͰܕఆٛ w +4ͷؔ਺Λ,PUMJOΒ͘͠ݺ΂ΔΑ͏ʹؔ਺ఆٛ +4੡ϥΠϒϥϦͷಋೖ fun ReactSwipeableProps.onChangeIndex(block: (Int) ->

    Unit) { onChangeIndex = { index: Int, _, _ -> block(index) } } // RComponentクラス内 override fun RBuilder.render() { swipeableViews { attrs.onChangeIndex { i -> setState { tabNumber = i } } } } BUUSTϓϩύςΟ͔Β1SPQT͕ੜ͑Δ ˠ֦ுؔ਺ݺͼग़͠
  62. Ͳ͏ͯ͠΋ॻ͖ํ͕෼͔Βͳ͍ʂ w KT  ϝιουҾ਺ʹੜͷ+4ίʔυΛจࣈྻͰ౉͢͜ͱ͕Ͱ͖Δ w +4ΛͱΓ͋͑ͣίϐϖˠগͣͭ͠,PUMJOʹม׵ +4੡ϥΠϒϥϦͷಋೖ inline fun

    Window.initMap() = js("""new window.google.maps.Map( document.getElementById('googleMap'), { center: { lat: 34.740864, lng: 139.391152 }, zoom: 11.3, mapTypeId: 'roadmap' } )""") ྫ(PPHMF.BQ"1*ͷॳظԽίʔυ
  63. ·ͱΊ ,PUMJO+4ͷ͜Ε͔Β w CBDLFOEͱGSPOUFOE͕ͭͷ,PUMJOϓϩδΣΫτʹ·ͱ·Δʂ w EBUBDMBTTͷڞ༗ɺ(SBEMFͰͷϏϧυɺ%4-ͰͷIUNMDTTهड़ ຊ൪ಋೖ΁ͷน w ѹ౗తͳࣄྫɾ৘ใෆ଍ʂɹϥΠϒϥϦ΋·ͩ·ͩগͳ͍ʂ w

    ؆୯ͳϞϊͰ΋࡞ͬͯެ։ˠ஌ݟͷ஝ੵɺ,PUMJO+4ͷલਐͷҰॿ ,PUMJOͰϑϩϯτΤϯυͷ։ൃ͕Ͱ͖Δͷ͸ָ͍͠ʂ ୔ࢁͷਓ͕৮ͬͯ͘ΕΔͱخ͍͠☺
  64. ίʔυϦʔσΟϯά LPUMJOSFBDU ʮ)FMMP 8PSMEʯΛදࣔ͢ΔαϯϓϧΞϓϦ class App : RComponent<RProps, RState>() {

    override fun RBuilder.render() { div { +"Hello, World!" } } } 3$PNQPOFOUʁ 3#VJMEFSʁ SFOEFSϝιου͸ ͳ֦ͥுؔ਺ʁ
  65. ίʔυϦʔσΟϯά LPUMJOSFBDU @ReactDsl open class RBuilder { val childList =

    mutableListOf<Any>() fun child(element: ReactElement): ReactElement { childList.add(element) return element } operator fun String.unaryPlus() { childList.add(this) } fun <P : RProps> child(type: Any, props: P, children: List<Any>) = child(createElement(type, props, *children.toTypedArray())) fun <P : RProps> child(type: Any, props: P, handler: RHandler<P>): ReactElement { val children = with(RElementBuilder(props)) { handler() childList } return child(type, props, children) } operator fun <P : RProps> RClass<P>.invoke(handler: RHandler<P>) = child(this, jsObject {}, handler) operator fun <T> RProvider<T>.invoke(value: T, handler: RHandler<RProviderProps<T>>) = child(this, jsObject { this.value = value }, handler) operator fun <T> RConsumer<T>.invoke(handler: RBuilder.(T) -> Unit) = child(this, jsObject<RConsumerProps<T>> { this.children = { value -> buildElements { handler(value) } } }) {} fun <P : RProps> RClass<P>.node( props: P, children: List<Any> = emptyList() ) = child(this, clone(props), children) fun <P : RProps, C : Component<P, *>> child(klazz: KClass<C>, handler: RHandler<P>): ReactElement { val rClass = klazz.js as RClass<P> return rClass(handler) } inline fun <P : RProps, reified C : Component<P, *>> child(noinline handler: RHandler<P>) = child(C::class, handler) fun <P : RProps, C : Component<P, *>> node( klazz: KClass<C>, props: P, children: List<Any> = emptyList() ): ReactElement { val rClass = klazz.js as RClass<P> return rClass.node(props, children) } inline fun <P : RProps, reified C : Component<P, *>> node(props: P, children: List<Any> = emptyList()) = node(C::class, props, children) fun RProps.children() { childList.addAll(Children.toArray(children)) } } 3#VJMEFSΫϥε
  66. ίʔυϦʔσΟϯά LPUMJOSFBDU 3#VJMEFSΫϥε w %0.ཁૉΛ֨ೲ͢ΔDIJME-JTUϓϩύςΟΛ࣋ͭ @ReactDsl open class RBuilder {

    val childList = mutableListOf<Any>() fun child(element: ReactElement): ReactElement { childList.add(element) return element } operator fun String.unaryPlus() { childList.add(this) } fun <P : RProps> child(type: Any, props: P, children: List<Any>) = child(createElement(type, props, *children.toTypedArray())) fun <P : RProps> child(type: Any, props: P, handler: RHandler<P>): ReactElement { val children = with(RElementBuilder(props)) { handler() childList } return child(type, props, children) } operator fun <P : RProps> RClass<P>.invoke(handler: RHandler<P>) = child(this, jsObject {}, handler) operator fun <T> RProvider<T>.invoke(value: T, handler: RHandler<RProviderProps<T>>) = child(this, jsObject { this.value = value }, handler) operator fun <T> RConsumer<T>.invoke(handler: RBuilder.(T) -> Unit) = child(this, jsObject<RConsumerProps<T>> { this.children = { value -> buildElements { handler(value) } } }) {} fun <P : RProps> RClass<P>.node( props: P, children: List<Any> = emptyList() ) = child(this, clone(props), children) fun <P : RProps, C : Component<P, *>> child(klazz: KClass<C>, handler: RHandler<P>): ReactElement { val rClass = klazz.js as RClass<P> return rClass(handler) } inline fun <P : RProps, reified C : Component<P, *>> child(noinline handler: RHandler<P>) = child(C::class, handler) fun <P : RProps, C : Component<P, *>> node( klazz: KClass<C>, props: P, children: List<Any> = emptyList() ): ReactElement { val rClass = klazz.js as RClass<P> return rClass.node(props, children) } inline fun <P : RProps, reified C : Component<P, *>> node(props: P, children: List<Any> = emptyList()) = node(C::class, props, children) fun RProps.children() { childList.addAll(Children.toArray(children)) } } @ReactDsl open class RBuilder { val childList = mutableListOf<Any>()
  67. ίʔυϦʔσΟϯά LPUMJOSFBDU 3#VJMEFSΫϥε w %0.ཁૉΛ֨ೲ͢ΔDIJME-JTUϓϩύςΟΛ࣋ͭ w DIJMEϝιουΛ࢖ͬͯཁૉΛ௥ՃͰ͖Δ @ReactDsl open class

    RBuilder { val childList = mutableListOf<Any>() fun child(element: ReactElement): ReactElement { childList.add(element) return element } operator fun String.unaryPlus() { childList.add(this) } fun <P : RProps> child(type: Any, props: P, children: List<Any>) = child(createElement(type, props, *children.toTypedArray())) fun <P : RProps> child(type: Any, props: P, handler: RHandler<P>): ReactElement { val children = with(RElementBuilder(props)) { handler() childList } return child(type, props, children) } operator fun <P : RProps> RClass<P>.invoke(handler: RHandler<P>) = child(this, jsObject {}, handler) operator fun <T> RProvider<T>.invoke(value: T, handler: RHandler<RProviderProps<T>>) = child(this, jsObject { this.value = value }, handler) operator fun <T> RConsumer<T>.invoke(handler: RBuilder.(T) -> Unit) = child(this, jsObject<RConsumerProps<T>> { this.children = { value -> buildElements { handler(value) } } }) {} fun <P : RProps> RClass<P>.node( props: P, children: List<Any> = emptyList() ) = child(this, clone(props), children) fun <P : RProps, C : Component<P, *>> child(klazz: KClass<C>, handler: RHandler<P>): ReactElement { val rClass = klazz.js as RClass<P> return rClass(handler) } inline fun <P : RProps, reified C : Component<P, *>> child(noinline handler: RHandler<P>) = child(C::class, handler) fun <P : RProps, C : Component<P, *>> node( klazz: KClass<C>, props: P, children: List<Any> = emptyList() ): ReactElement { val rClass = klazz.js as RClass<P> return rClass.node(props, children) } inline fun <P : RProps, reified C : Component<P, *>> node(props: P, children: List<Any> = emptyList()) = node(C::class, props, children) fun RProps.children() { childList.addAll(Children.toArray(children)) } } fun child(element: ReactElement): ReactElement { childList.add(element) return element }
  68. @ReactDsl open class RBuilder { val childList = mutableListOf<Any>() fun

    child(element: ReactElement): ReactElement { childList.add(element) return element } operator fun String.unaryPlus() { childList.add(this) } fun <P : RProps> child(type: Any, props: P, children: List<Any>) = child(createElement(type, props, *children.toTypedArray())) fun <P : RProps> child(type: Any, props: P, handler: RHandler<P>): ReactElement { val children = with(RElementBuilder(props)) { handler() childList } return child(type, props, children) } operator fun <P : RProps> RClass<P>.invoke(handler: RHandler<P>) = child(this, jsObject {}, handler) operator fun <T> RProvider<T>.invoke(value: T, handler: RHandler<RProviderProps<T>>) = child(this, jsObject { this.value = value }, handler) operator fun <T> RConsumer<T>.invoke(handler: RBuilder.(T) -> Unit) = child(this, jsObject<RConsumerProps<T>> { this.children = { value -> buildElements { handler(value) } } }) {} fun <P : RProps> RClass<P>.node( props: P, children: List<Any> = emptyList() ) = child(this, clone(props), children) fun <P : RProps, C : Component<P, *>> child(klazz: KClass<C>, handler: RHandler<P>): ReactElement { val rClass = klazz.js as RClass<P> return rClass(handler) } inline fun <P : RProps, reified C : Component<P, *>> child(noinline handler: RHandler<P>) = child(C::class, handler) fun <P : RProps, C : Component<P, *>> node( klazz: KClass<C>, props: P, children: List<Any> = emptyList() ): ReactElement { val rClass = klazz.js as RClass<P> return rClass.node(props, children) } inline fun <P : RProps, reified C : Component<P, *>> node(props: P, children: List<Any> = emptyList()) = node(C::class, props, children) fun RProps.children() { childList.addAll(Children.toArray(children)) } } ίʔυϦʔσΟϯά LPUMJOSFBDU 3#VJMEFSΫϥε w %0.ཁૉΛ֨ೲ͢ΔDIJME-JTUϓϩύςΟΛ࣋ͭ w DIJMEϝιουɺଞʹͭ w 3$PNQPOFOUΛ௥Ճ w QSPQTͱࢠཁૉΛݸผͷҾ਺Ͱ௥ՃFUD fun child(type: Any, props: P, children: List<Any>): ReactElement fun child(type: Any, props: P, handler: RHandler<P>): ReactElement fun child(klazz: KClass<C>, handler: RHandler<P>): ReactElement inline fun child(noinline handler: RHandler<P>): ReactElement
  69. ίʔυϦʔσΟϯά LPUMJOSFBDU EJWϝιου w 3#VJMEFSͷ֦ுؔ਺ͱͯ͠ఆٛ w Ҿ਺CMPDLͷܕ͸3%0.#VJMEFS%*7 6OJU w CMPDLͷதͰEJW΍ͦͷଞ)UNM5BHͷϝιουΛ࠶ؼతʹهड़Ͱ͖Δʂ

    w )UNM5BH༻ϝιου͸શ֦ͯுؔ਺ˠ3#VJMEFS͕ͪ͝Ό͔ͭͳ͍ʂ inline fun RBuilder.div( classes: String? = null, block: RDOMBuilder<DIV>.() -> Unit ): ReactElement = tag(block) { DIV(attributesMapOf("class", classes), it) } 3%0.#VJMEFS ˠ3#VJMEFSͷࢠΫϥε EJW\ TQBO\ B\^ ^ ^
  70. ίʔυϦʔσΟϯά LPUMJOSFBDU UBHϝιου w )UNM5BH༻ϝιου͔Β࣮ࡍʹݺͼग़͞ΕΔϝιου w 3#VJMEFSDIJME  ϝιουΛ࣮ߦ w

    ,PUMJO+4Ͱಠࣗ)5.-λάΛѻ͍͍ͨʂˠUBHϝιουͰΑ͠ͳʹ inline fun <T : Tag> RBuilder.tag( block: RDOMBuilder<T>.() -> Unit, noinline factory: (TagConsumer<Unit>) -> T ): ReactElement = child(RDOMBuilder(factory).apply { block() }.create())
  71. ίʔυϦʔσΟϯά LPUMJOSFBDU 3#VJMEFSΫϥε w 4USJOHVOBSZ1MVT ϝιου w ԋࢉࢠΦʔόʔϩʔυ ˠจࣈྻͷ୯߲ԋࢉ IPHF

    Λ্ॻ͖ w 3#VJMEFSΫϥεͷ಺෦Ͱએݴ ɹˠUIJT͕3#VJMEFSͷ࣌ͷΈ༗ޮ ɹɹར༻ൣғΛݶఆ͠ɺ෭࡞༻Λ཈͑Δʂ @ReactDsl open class RBuilder { val childList = mutableListOf<Any>() fun child(element: ReactElement): ReactElement { childList.add(element) return element } operator fun String.unaryPlus() { childList.add(this) } fun <P : RProps> child(type: Any, props: P, children: List<Any>) = child(createElement(type, props, *children.toTypedArray())) fun <P : RProps> child(type: Any, props: P, handler: RHandler<P>): ReactElement { val children = with(RElementBuilder(props)) { handler() childList } return child(type, props, children) } operator fun <P : RProps> RClass<P>.invoke(handler: RHandler<P>) = child(this, jsObject {}, handler) operator fun <T> RProvider<T>.invoke(value: T, handler: RHandler<RProviderProps<T>>) = child(this, jsObject { this.value = value }, handler) operator fun <T> RConsumer<T>.invoke(handler: RBuilder.(T) -> Unit) = child(this, jsObject<RConsumerProps<T>> { this.children = { value -> buildElements { handler(value) } } }) {} fun <P : RProps> RClass<P>.node( props: P, children: List<Any> = emptyList() ) = child(this, clone(props), children) fun <P : RProps, C : Component<P, *>> child(klazz: KClass<C>, handler: RHandler<P>): ReactElement { val rClass = klazz.js as RClass<P> return rClass(handler) } inline fun <P : RProps, reified C : Component<P, *>> child(noinline handler: RHandler<P>) = child(C::class, handler) fun <P : RProps, C : Component<P, *>> node( klazz: KClass<C>, props: P, children: List<Any> = emptyList() ): ReactElement { val rClass = klazz.js as RClass<P> return rClass.node(props, children) } inline fun <P : RProps, reified C : Component<P, *>> node(props: P, children: List<Any> = emptyList()) = node(C::class, props, children) fun RProps.children() { childList.addAll(Children.toArray(children)) } } operator fun String.unaryPlus() { childList.add(this) }