Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[ 改訂版 ] Cycle.js - リアクティブ・プログラミングに特化した JS フレームワーク

[ 改訂版 ] Cycle.js - リアクティブ・プログラミングに特化した JS フレームワーク

[ 追記 ] Meguro.es x Gotanda.js #1 にて発表した際の資料です。Node学園 25時限目 での内容に一部誤りがあったので訂正しました。

------

Node学園 25時限目 ( 2017年4月24日 ) にて発表した際の資料です。
Cycle.js という JS フレームワークの概要と仕組みについて簡単にご紹介しています。

こちらのブログ記事にてより詳しく解説していますので、併せて御覧ください。
https://tech.recruit-mp.co.jp/front-end/post-11898/

wakamsha

April 25, 2017
Tweet

More Decks by wakamsha

Other Decks in Programming

Transcript

  1. $ZDMFKT
    ϦΞΫςΟϒɾϓϩάϥϛϯάʹಛԽͨ͠+4ϑϨʔϜϫʔΫ
    - A functional and reactive JavaScript framework for predictable code -

    /BPLJ:"."%"
    !XBLBNTIB
    /PEFֶԂ࣌ݶ໨.FHVSPFTº(PUBOEBKT

    View full-size slide

  2. 8IBU`T$ZDMFKT
    $ZDMFKTͬͯԿʁ

    View full-size slide

  3. 7JSUVBM%0.
    0CTFSWBCMF
    0CTFSWBCMFͱ7JSUVBM%0.Λ
    XFCΞϓϦ։ൃ͠΍͘͢͢ΔͨΊʹʰബ͘ʱϥοϓͨ͠΋ͷ
    8IBU`T$ZDMFKT

    View full-size slide

  4. -JCSBSJFTUIBUTVQQPSU$ZDMFKT

    View full-size slide

  5. YTUSFBN3Y+4
    w 0CTFSWBCMFTͱ͍͏ΞʔΩςΫνϟΛ༻͍ͨϦΞΫςΟϒϓ
    ϩάϥϛϯά༻ͷϥΠϒϥϦ
    w ඇಉظॲཧΛ؆͔ܿͭՄಡੑߴ͘ίʔσΟϯάͰ͖Δ
    w YTUSFBN͸3T+4ͷܰྔ൛
    w ˞ΦϖϨʔλͷ਺΍ϝιου໊͕Ұ෦ҟͳΔ
    w 3Y+4Ͱͷ୅༻΋Մೳ
    w ˞Ұ෦Ωϟετ͕ඞཁ

    View full-size slide

  6. 4OBCCEPN
    w Ծ૝%0.ΛૢΔγϯϓϧͳϥΠϒϥϦ
    w ϞδϡʔϧػೳΛ༗͓ͯ͠Γɺػೳ֦ு͕༰қʹՄೳ
    w %0.ੜ੒෦෼͸)ZQFS4DSJQUͷΞʔΩςΫνϟΛ࠾༻
    w div()΍input()ͳͲ)5.-λά໊ͦͷ··ͷϝιο
    υ໊͕༻ҙ͞Ε͍ͯΔ

    View full-size slide

  7. #BTJD&YBNQMF
    ಈ͔ͯ͠ΈΑ͏

    View full-size slide

  8. #BTJD&YBNQMF

    View full-size slide

  9. import {Observable} from 'rxjs';
    import {div, label, input, hr, h1, VNode, makeDOMDriver} from '@cycle/dom';
    import {run} from '@cycle/rxjs-run';
    import {DOMSource} from '@cycle/dom/rxjs-typings';
    type Sources = {
    DOM: DOMSource;
    }
    type Sinks = {
    DOM: Observable;
    }
    /**
    * ΞϓϦέʔγϣϯ
    * @param sources
    * @returns {{DOM: Observable}}
    */
    function main(sources: Sources): Sinks {
    // ΩʔೖྗΠϕϯτΛऔಘ ( Intent )
    const input$: Observable = sources.DOM.select('.field').events('input');
    // ೖྗΠϕϯτ͔Βݱࡏͷঢ়ଶͳ͍͠஋Λऔಘ ( Model )
    const name$: Observable = Observable.from(input$)
    .map((ev: Event) => ev.target.value)
    .startWith('');
    // ݱࡏͷঢ়ଶΛը໘ʹඳը ( View )
    const vdom$: Observable = name$.map(name => {

    View full-size slide

  10. /**
    * ΞϓϦέʔγϣϯ
    * @param sources
    * @returns {{DOM: Observable}}
    */
    function main(sources: Sources): Sinks {
    // ΩʔೖྗΠϕϯτΛऔಘ ( Intent )
    const input$: Observable = sources.DOM.select('.field').events('input');
    // ೖྗΠϕϯτ͔Βݱࡏͷঢ়ଶͳ͍͠஋Λऔಘ ( Model )
    const name$: Observable = Observable.from(input$)
    .map((ev: Event) => ev.target.value)
    .startWith('');
    // ݱࡏͷঢ়ଶΛը໘ʹඳը ( View )
    const vdom$: Observable = name$.map(name => {
    return div('.well', [
    div('.form-group', [
    label('Name: '),
    input('.field.form-control', {attrs: {type: 'text'}}),
    ]),
    hr(),
    h1(`Hello ${name}`)
    ]);
    });
    // ݁ՌΛυϥΠόʹग़ྗ͢Δ ( Sinks )
    return {
    DOM: vdom$
    };
    }

    View full-size slide

  11. label('Name: '),
    input('.field.form-control', {attrs: {type: 'text'}}),
    ]),
    hr(),
    h1(`Hello ${name}`)
    ]);
    });
    // ݁ՌΛυϥΠόʹग़ྗ͢Δ ( Sinks )
    return {
    DOM: vdom$
    };
    }
    // ΞϓϦέʔγϣϯ͔Βͷ໭Γ஋Λड͚औΔυϥΠό܈Λఆٛ
    const drivers = {
    DOM: makeDOMDriver('#app-container')
    };
    // ΞϓϦέʔγϣϯͱυϥΠόΛ݁ͼ͚ͭΔ
    run(main, drivers);

    View full-size slide

  12. label('Name: '),
    input('.field.form-control', {attrs: {type: 'text'}}),
    ]),
    hr(),
    h1(`Hello ${name}`)
    ]);
    });
    // ݁ՌΛυϥΠόʹग़ྗ͢Δ ( Sinks )
    return {
    DOM: vdom$
    };
    }
    // ΞϓϦέʔγϣϯ͔Βͷ໭Γ஋Λड͚औΔυϥΠό܈Λఆٛ
    const drivers = {
    DOM: makeDOMDriver('#app-container')
    };
    // ΞϓϦέʔγϣϯͱυϥΠόΛ݁ͼ͚ͭΔ
    run(main, drivers);

    View full-size slide

  13. %FTJHOQIJMPTPQIZPG$ZDMFKT
    $ZDMFKTͷઃܭࢥ૝

    View full-size slide

  14. Application
    Application
    %FTJHOQIJMPTPQIZPG$ZDMFKT

    View full-size slide

  15. driver()
    main()
    %FTJHOQIJMPTPQIZPG$ZDMFKT

    View full-size slide

  16. driver()
    main()
    ෭࡞༻ ( Effective )
    DOM API
    %FTJHOQIJMPTPQIZPG$ZDMFKT

    View full-size slide

  17. driver()
    main()
    ෭࡞༻ ( Effective )
    DOM API
    Source
    Stream
    %FTJHOQIJMPTPQIZPG$ZDMFKT

    View full-size slide

  18. driver()
    main()
    ঢ়ଶ ( State )
    ෭࡞༻ ( Effective )
    DOM API
    Source
    Stream
    %FTJHOQIJMPTPQIZPG$ZDMFKT

    View full-size slide

  19. driver()
    main()
    ঢ়ଶ ( State )
    ෭࡞༻ ( Effective )
    DOM API
    Source
    Stream
    Sink
    Stream
    %FTJHOQIJMPTPQIZPG$ZDMFKT

    View full-size slide

  20. Rx.Observable
    .timer(0, 1000)
    .map(i => `Seconds elapsed: ${i}`)
    .subscribe(
    (text: string) => {
    const container = document.querySelector('#app');
    container.textContent = text;
    }
    );
    ঢ়ଶ ( State )
    ෭࡞༻ ( Effective )
    %FTJHOQIJMPTPQIZPG$ZDMFKT

    View full-size slide

  21. Rx.Observable
    .timer(0, 1000)
    .map(i => `Seconds elapsed: ${i}`)
    .subscribe(
    (text: string) => {
    const container = document.querySelector('#app');
    container.textContent = text;
    }
    );
    ঢ়ଶ ( State )
    ෭࡞༻ ( Effective )
    %FTJHOQIJMPTPQIZPG$ZDMFKT

    View full-size slide

  22. Rx.Observable
    .timer(0, 1000)
    .map(i => `Seconds elapsed: ${i}`)
    .subscribe(
    (text: string) => {
    const container = document.querySelector('#app');
    container.textContent = text;
    }
    );
    Observable
    Subject
    ঢ়ଶ ( State )
    ෭࡞༻ ( Effective )
    %FTJHOQIJMPTPQIZPG$ZDMFKT

    View full-size slide

  23. function main() {
    return Rx.Observable
    .timer(0, 1000)
    .map(i => `Seconds elapsed: ${i}`);
    }
    function DOMDriver(text$: Observable) {
    text$.subscribe(
    (text: string) => {
    const container = document.querySelector('#app');
    container.textContent = text;
    }
    );
    }
    Observable
    Subject
    %FTJHOQIJMPTPQIZPG$ZDMFKT

    View full-size slide

  24. function main() {
    return Rx.Observable
    .timer(0, 1000)
    .map(i => `Seconds elapsed: ${i}`);
    }
    function DOMDriver(text$: Observable) {
    text$.subscribe(
    (text: string) => {
    const container = document.querySelector('#app');
    container.textContent = text;
    }
    );
    }
    // Run
    const sink = main();
    DOMDriver(sink);

    View full-size slide

  25. function main() {
    return Rx.Observable
    .timer(0, 1000)
    .map(i => `Seconds elapsed: ${i}`);
    }
    function DOMDriver(text$: Observable) {
    text$.subscribe(
    (text: string) => {
    const container = document.querySelector('#app');
    container.textContent = text;
    }
    );
    }
    // Run
    const sink = main();
    DOMDriver(sink);
    // υϥΠό܈Λఆٛ

    const drivers = {

    DOM: makeDOMDriver('#app')

    };

    // main ͱυϥΠόΛ݁ͼ͚ͭΔ

    run(main, drivers);

    View full-size slide

  26. *OUSPEVDFNZTFMG
    Զͷ໊લΛݴͬͯΈΖ
    ࣗݾ঺հ

    View full-size slide

  27. גࣜձࣾϦΫϧʔτϚʔέςΟϯάύʔτφʔζ
    XFCϑϩϯτΤϯυΤϯδχΞ
    ࢁా ௚थ
    /BPLJ:"."%"
    *OUSPEVDFNZTFMG
    !XBLBNTIB

    View full-size slide

  28. http://tech.recruit-mp.co.jp
    NET BIZ DIV. TECH BLOG

    View full-size slide

  29. http://tech.recruit-mp.co.jp
    3.1 ϒϩά

    View full-size slide