Slide 1

Slide 1 text

*NNVUBCMF+4Λ࢖ͬͨ εέʔϥϒϧͳ 3FBDUΞϓϦέʔγϣϯ։ൃ %*((-&גࣜձࣾ$50ਫ্ॣ

Slide 2

Slide 2 text

ࣗݾ঺հ %*((-&גࣜձࣾ औక໾$50 ਫ্ॣ ࡀҐdϨϯλϧνϟοτͷΫϥοΩϯάΛ࢝Ίͯϓ ϩάϥϛϯάσϏϡʔ 1)1 1FSM $ 8JO"1*ͱ͔৮ͬͯ·ͨ͠ େֶd਺ֶઐ߈ ໊ݹ԰େ େֶӃdʮఆཧূ໌ࢧԉܥʯͷݚڀ ˣ ๭ελʔτΞοϓ ˣ ϑϦʔϥϯε ˣ %*((-&૑ۀ೥໨ˡࠓ͜͜

Slide 3

Slide 3 text

*OEFY w lෆมੑzΛऔΓѻ͏ w *NNVUBCMF+4ͱ͸ w 3FBDUͱͷ૬ੑ͸Կނྑ͍ʁ w *NNVUBCMF+4ͷ࢖͍ํ w %*((-&Ͱͷ׆༻5JQT

Slide 4

Slide 4 text

ෆมੑΛऔΓѻ͏

Slide 5

Slide 5 text

ෆมͰ͋Δͱ͸Կ͔

Slide 6

Slide 6 text

+4ͷΦϒδΣΫτ͸ෆมͰͳ͍ const someObj = { x: 1 }; bigOperation(someObj); if (someObj.x !== 1) { throw ‘BUG!'; } ෆมͰ͸ͳ͍

Slide 7

Slide 7 text

+4ͷΦϒδΣΫτ͸ෆมͰͳ͍ όάͬͨΒ ͜͜ΛಡΈղ͔ͳ͍ͱ͍͚ͳ͍ const someObj = { x: 1 }; bigOperation(someObj); if (someObj.x !== 1) { throw ‘BUG!'; } ෆมͰ͸ͳ͍

Slide 8

Slide 8 text

+4ͷΦϒδΣΫτ͸ෆมͰͳ͍ όάͬͨΒ ͜͜ΛಡΈղ͔ͳ͍ͱ͍͚ͳ͍ const someObj = { x: 1 }; bigOperation(someObj); if (someObj.x !== 1) { throw ‘BUG!'; } ਺ઍߦ͔΋͠Εͳ͍ɻਏ͍ɻ

Slide 9

Slide 9 text

+4ͷΦϒδΣΫτ͸ෆมͰͳ͍ const someObj = ImmutableSomething({ x: 1 }); bigOperation(someObj); if (someObj.x !== 1) { throw ‘BUG!'; } ෆมͳΒ͹ɺ ͜ͷόά͸ى͖ͳ͍

Slide 10

Slide 10 text

Կ͕ݴ͍͍͔ͨ ݁࿦ ෆมͰͳ͍㱺Զͨͪͷ࢓ࣄ͕૿͑Δ

Slide 11

Slide 11 text

Կ͕ݴ͍͍͔ͨ ݁࿦ ෆมͰͳ͍㱺Զͨͪͷ࢓ࣄ͕૿͑Δ ˠѱ

Slide 12

Slide 12 text

ෆมͳ΋ͷ͕ཉ͍͠ ͋Γ·ͤΜ

Slide 13

Slide 13 text

ෆมͳ΋ͷ͕ཉ͍͠ ˣ ࡞Δ͔͠ͳ͍ ͋Γ·ͤΜ

Slide 14

Slide 14 text

ෆมͳ΋ͷ͕ཉ͍͠ ˣ ࡞Δ͔͠ͳ͍ ͋Γ·ͤΜ ˣ ෆมΦϒδΣΫτര஀

Slide 15

Slide 15 text

ෆมΦϒδΣΫτ +BWBͷ΍Γํ ɾpOBMͱ͔ࢦఆ ɾHFUUFS͔͠࡞Βͳ͍ final class Person { private final String name; public Person(String name) { this.name = name; } public String getName() { return this.name; } }

Slide 16

Slide 16 text

ෆมΦϒδΣΫτ *O+BWB4DSJQU ɾશͯϝϯόΞΫηεՄೳ ɹɾΞϯείͰӅ͢ ɾHFUUFSΛ࡞Δ class Person { constructor(name) { this._name = name; } get name() { return this._name; } } ˞ &DNB4DSJQUͷ4UBHF1SPQPTBMΛڐ༰͢Δ৔߹ɺ QSJWBUFDMBTTpFMETͱ͍͏ख΋͋Δ https://github.com/tc39/proposal-class-fields

Slide 17

Slide 17 text

ෆมΦϒδΣΫτ ଞʹ΋ෆมΦϒδΣΫτʹٻΊΒΕΔ΋ͷ ɾ"SSBZ .BQ౳ͷϓϦϛςΟϒͷෆมόʔδϣϯ ɾ౳Ձੑ൑ఆ ɾ1MBJO0CKFDUͱͷؒͷΤϯίʔυσίʔυ ˠͦΕ*NNVUBCMF+4ʹ͋Γ·͢

Slide 18

Slide 18 text

*NNVUBCMF+4ͱ͸

Slide 19

Slide 19 text

*NNVUBCMF+4ͱ͸ σʔλߏ଄ *NNVUBCMF+4 1MBJO+4 ഑ྻ -JTU "SSBZ ,FZ7BMVFϚοϓ .BQ0SEFSFE.BQ .BQ8FBL.BQ0CKFDU ॏෳͳ͠ू߹ 4FU0SEFSFE4FU 4FU8FBL4FU ஗ԆϦετ 4FR ͳ͠ ελοΫ 4UBDL ͳ͠ ೚ҙͷߏ଄ମ 3FDPSE DMBTTఆٛ0CKFDU ڧྗͳϓϦϛςΟϒΛؚΉɺෆมΦϒδΣΫτΛऔΓѻ͏ϥΠϒϥϦ

Slide 20

Slide 20 text

*NNVUBCMF+4ͷྑ͍ͱ͜Ζ ࣮૷ʹݎ࿚ͳ੍໿Λ͔͚ΒΕΔ ੜ+4ʹ͋Γ͕ͪͳࡶͳ࣮૷͕ຮԆ͢ΔͷΛ཈͑Δ EFFQDPQZΛෆཁʹͰ͖Δ JNNVUBCMF͔ͩΒ౰વ ౳Ձੑ൑ఆ͕༻ҙ͞Ε͍ͯΔ +4ͷFRVBMJUZ࣮૷͸൥ࡶʹͳΓ͕ͪ ϓϦϛςΟϒ -JTU΍.BQ ͕ͦͦ͜͜Ϧον

Slide 21

Slide 21 text

3FBDUͱͷ૬ੑ͸Կނྑ͍ʁ

Slide 22

Slide 22 text

جຊతʹ3FBDU͸ॻ͖׵͑Λਪ঑͍ͯ͠ͳ͍

Slide 23

Slide 23 text

࣮૷্ɺTUBUF΍QSPQTͷσʔλͷॻ͖׵͕͑ඞཁʹͳΔέʔε͸΄΅ͳ͍ // bad handleSelect(id) { const { selectedIds } = this.state; selectedIds.push(id); this.setState({ selectedIds, }); } // good handleSelect(id) { const { selectedIds } = this.state; this.setState({ selectedIds: [...selectedIds, id], }); } ͔͠͠ɺهड़͕໘౗ ಛʹ0CKFDUͷDPQZ *NNFS΍JNNVUBCJMJUZIFMQFSΛ࢖ͬͨͱͯ͠΋ɺ ഁյతॻ͖ํΛ཈ࢭͰ͖ΔΘ͚Ͱ͸ͳ͍ ഁյత

Slide 24

Slide 24 text

*NNVUBCMF+4৔߹ // ImmutableJS List handleSelect(id) { const { selectedIds } = this.state; this.setState({ selectedIds: selectedIds.push(id), }); } ͍͕ͭ͜*NNVUBCMF-JTUʹͳͬͨ৔߹ -JTUQVTIͷ݁Ռ͸৽͍͠-JTUΠϯελϯε ίʔυ͕୹͘ɺ͔ͭඇഁյత

Slide 25

Slide 25 text

ڧྗͳྫ ͩΊͩΑͶ ਖ਼͍͕͠ɺOFX͢Δͷ͸حົ class User { constructor(name, age) { this.name = name; this.age = age; } } // bad handleChangeName(name) { const { user } = this.state; user.name = name; this.setState({ user, }); } // good handleChangeName(name) { const { user } = this.state; this.setState({ user: new User(name, user.age), }); }

Slide 26

Slide 26 text

class User extends Immutable.Record({ name: '', age: 0, }) { } // bad handleChangeName(name) { const { user } = this.state; user.name = name; // will throw "Error: Cannot set on an immutable record." this.setState({ user, }); } // good handleChangeName(name) { const { user } = this.state; this.setState({ user: user.set('name', name), }); } ڧྗͳྫ ྫ֎Ͱམͪͯ͘ΕΔʢૉ੖Β͍͠ΑͶ ʣ ˠ։ൃʹྑ੍͍໿Λ͔͚ͯ͘ΕΔ 3FDPSETFU͸৽͍͠ΠϯελϯεΛฦ͢

Slide 27

Slide 27 text

*NNVUBCMF+4ͷ࢖͍ํ ˞ͬ͟ͱྲྀ͢ͷͰɺؾʹͳΔํ͸࣭໰͍ͩ͘͞

Slide 28

Slide 28 text

*NNVUBCMF-JTU ෆมͷ഑ྻ // init with Array const l1 = List([4, 2, 3]); // => List [4, 2, 3] // #get(index) to get value at index l1.get(1) // => 2 // #set(index, value) to set value at index const l2 = l1.set(0, 1); // => List [1, 2, 3] l1 // => List [4, 2, 3] <- not mutated // generic operations like map, forEach and reduce can be used const l3 = l2.map(x => 1 + x) // => List [2, 3, 4] // #delete(index) to delete #unshift(value) to add at first const l4 = l3.delete(2).unshift(4) // => List [4, 2, 3] // equality l1.equals(l4) // => true l1.equals(l2) // => false

Slide 29

Slide 29 text

*NNVUBCMF.BQ ෆมͷ,FZ7BMVF.BQ // init with entries const m1 = Map([['a', 1], ['b', 2]]) // => Map { "a": 1, "b": 2 } // #get(key) to get value at key m1.get('b') // => 2 // #set(key, value) to set value at key const m2 = m1.set('c', 3); // => Map { "a": 1, "b": 2, "c": 3 } m1 // Map { "a": 1, "b": 2 } <- not mutated // key can be non-string value const m3 = m2.set(5, 4) // => Map { "a": 1, "b": 2, "c": 3, 5: 4 } // key type is NOT converted implicitly m3.get('5') // => undefined m3.get(5) // => 4 // #delete(key) to delete key-value pair const m4 = m3.delete(5).delete('c'); // => Map { "a": 1, "b": 2 } // equality m1.equals(m4) // => true m1.equals(m2) // => false

Slide 30

Slide 30 text

*NNVUBCMF4FU ෆมͷॏෳͳ͠ू߹ // init with Array const s1 = Set([1, 2, 3]) // => Set [1, 2, 3] // #has(value) to check value presence // NOTE: Set#has is potentially faster O(logN) than Array#includes O(N) s1.has(2) // => true // Set#add(value) to add new value s1.add(3) // => Set [1, 2, 3] <- duplicated, no change const s2 = s1.add(4) // => Set [1, 2, 3, 4] // Set#delete(value) to delete value from set const s3 = s2.delete(1) // => Set [2, 3, 4] // set-theoretical operations s1.intersect(s3) // => Set [2, 3] <- S1 ∩ S3 s1.union(s2) // => Set [1, 2, 3, 4] <- S1 ∪ S3 s1.subtract(s3) // => Set [1] <- S1 \ S3

Slide 31

Slide 31 text

ଞͷϓϦϛςΟϒ ஗ԆϦετ const s1 = Seq([1, 2, 3]) const s2 = s1.map(x => { console.log(`mapping ${x}`) return x % 2 === 0 ? x / 2 : null; }) const s3 = s2.filter(x => { console.log(`filtering ${x}`); return x !== null; }) s3.toList() // mapping 1 // filtering null // mapping 2 // filtering 1 // mapping 3 // filtering null // => List [ 1 ]

Slide 32

Slide 32 text

class User extends Immutable.Record({ firstName: '', lastName: '', age: 0, }) { get fullName() { return `${this.firstName} ${this.lastName}` } } // initialize const u = new User({ firstName: 'Shun', lastName: 'Mizukami', age: 29 }) // to get value u.firstName // => "Shun" // cant set value u.firstName = "Taro" // => error thrown // invoke instance method u.fullName // => "Shun Mizukami" // Record#set to set and return new instance u.set('age', 30) // => User { firstName: "Shun", lastName: "Mizukami", age: 30 } *NNVUBCMF3FDPSE ϞσϧΛ࡞ΕΔ

Slide 33

Slide 33 text

%*((-&Ͱͷ׆༻ํ๏

Slide 34

Slide 34 text

.PEFM͸΄΅શͯ*NNVUBCMF3FDPSE frontend/ + src/ + Components/ + Models/ ΄΅RecordΫϥε + ViewModels/ ΄΅RecordΫϥε :

Slide 35

Slide 35 text

ॏΊͷॲཧͳΒNFNPJ[F͢Δ class User extends Record({ firstName: '', lastName: '', age: 0, }) { @memoize get fullName() { return `${this.firstName} ${this.lastName}` } } σʔλ͕ෆมͳͷͰϝϞԽͰؒҧͬͨΩϟογϡΛ͢Δ৺഑͕ͳ͍ ˞NFNPJ[FEFDPSBUPS

Slide 36

Slide 36 text

3FDPSEͷϞσϧʹQSPQ5ZQFTΛॻ͘ import IPT from 'react-immutable-proptypes'; import PT from 'proptypes'; class User extends Record({ firstName: '', lastName: '', age: 0, }) { // User.t as a PropTypes static t = IPT.recordOf({ firstName: PT.string, lastName: PT.string, age: PT.number, }) get fullName() { return `${this.firstName} ${this.lastName}` } } ˞JNNVUBCMF޲͚1SPQ5ZQFTϥΠϒϥϦ ˞.PEFMʹॻ͘͜ͱͰɺ.PEFMUͰ࢖͑Δ

Slide 37

Slide 37 text

// Unofficial Record inheritance helper // https://gist.github.com/mizukami234/5bd93a91f632fa8b2a984c32d2ff408e import RecordExtend from 'Utils'; class Vec2 extends Record({ x: 0, y: 0, }) { get sum() { return this.x + this.y; } } class Vec3 extends RecordExtend(Vec2, { z: 0, }) { get sum() { return super.sum + this.z; } } 3FDPSEΫϥεͷܧঝ ඇެࣜ ಺෦࣮૷্ɺ௨ৗͷܧঝ͸Ͱ͖ͳ͍ (JTUʹ͍͋͛ͯ·͢

Slide 38

Slide 38 text

·ͱΊ *NNVUBCMF+4͸ΠΠͧɻ

Slide 39

Slide 39 text

"QQFOEJY

Slide 40

Slide 40 text

// example: List // creates 100 instances and destroyed except the last one let l = List() for (let i = 0; i < 100; i++) { l = l.push(i) } // withMutations passes mutable instance enabled within a limited scope const l = List().withMutations(m => { for (let i = 0; i < 100; i++) { m.push(i) } }) ͦ͏͸ݴͬͯ΋ɺύϑΥʔϚϯεతʹ .VUBUJPO͕ཉ͍͠৔߹ ຖճੜ੒͢Δ ͜ͷதͰ͚ͩNVUBCMFʹͳΔ

Slide 41

Slide 41 text

5ZQF4DSJQUରԠ͸Ͳ͏ͳͷ͔ w ͋Δఔ౓͸ରԠ͍ͯ͠ΔʢιʔεݟΔݶΓʣ w *NNVUBCMFͰ͋Δ͓͔͛Ͱɺ$PWBSJBOU΍ $POUSBWBSJBOU͸݈શʹ࢖͑Δ ͱࢥ͏ w TFU*O VQEBUF*Oͱ͍ͬͨϝιου͸ਖ਼͘͠ܕ෇͚Ͱ͖ ͳ͍ͬΆ͍

Slide 42

Slide 42 text

஫ҙ͢΂͖͜ͱ w ϝϯςφʔͷਓ͕࠷ۙ΍Δؾ͕ͳ͍ w 3FDPSEʹDPOTUSVDUPSΛॻ͍ͯ͸͍͚ͳ͍ w TFU౳Λͨ͠ͱ͖ʹݺ͹Εͳ͍ w 3FDPSEͷΠϯελϯεϝιουΛBSSPXͰॻ͍ͯ͸͍ ͚ͳ͍ w CBCFMʹΑͬͯDPOTUSVDUPS্ʹల։͞ΕΔͨΊ