Slide 1

Slide 1 text

React.js, Draft.jsͰ࡞Δ ϦονςΩετΤσΟλ։ൃೖ໳ Meguro.es #4 @Wantedly ஛ຊ ༤و (@mottox2)

Slide 2

Slide 2 text

γΰτͰίίϩΦυϧ ࣗݾ঺հ ஛ຊ ༤و @mottox2 • Wantedly৽ଔҰ೥໨ͷΤϯδχΞ • ϑϩϯτΤϯυ͕޷͖ • ʮϑΟʔυʯΛ࡞͍ͬͯ·͢

Slide 3

Slide 3 text

දݱͷ෯Λ޿͛ΔͨΊʹ ϒϩάΤσΟλͷϦχϡʔΞϧΛߦͬͨ

Slide 4

Slide 4 text

γΰτͰίίϩΦυϧ ϦονςΩετΤσΟλ։ൃ ϦονςΩετΤσΟλͷඞཁੑ ΤϯδχΞք۾ͰϚʔΫμ΢ϯʴϓϨϏϡʔ͕ྲྀߦ͍ͬͯΔɻ ී௨ͷਓ͔Βͨ͠ΒϦονςΩετΤσΟλ͕౰ͨΓલɻ ʮฤू͍ͯ͠Δݟͨ໨ʹެ։͞ΕΔ΋ͷʯͰ͋ͬͯཉ͍͠͸ͣɻ ϦονςΩετΤσΟλ։ൃͷਏ͞ (=contenteditableͱͷઓ͍) ᶃ ϒϥ΢βʹΑͬͯڍಈ͕ҧ͏ ᶄ ཤྺ؅ཧ͕େม ᶅ DOMΛ৮Δඞཁ͕͋Δ

Slide 5

Slide 5 text

γΰτͰίίϩΦυϧ ͜Ε·Ͱ ҎલͷΤσΟλ React+Reduxߏ੒ͷதͰɺੜ ͷDOMΛ͍͍ͬͯͨ͡ɻ ֦ுͣ͠Β͍ DOMΛ௚઀৮ͬͯ؅ཧ͍ͯ͠Δ෦෼

Slide 6

Slide 6 text

γΰτͰίίϩΦυϧ Draft.jsͱ͸ʁ Facebookͷެ։͍ͯ͠ΔOSSɻ React.js্ͰϦονςΩετΤσΟλΛߏங͢ΔͨΊͷίϯϙʔωϯτΛఏڙ͠ ͯ͘ΕΔɻ https://github.com/facebook/draft-js Ըܙ ᶃ ϒϥ΢βؒͷڍಈͷࠩΛٵऩͯ͘͠ΕΔɻ ᶄ ΤσΟλશମΛ1ͭͷStateͱͯ͠؅ཧ͢Δ͔Βɺཤྺ؅ཧ΋؆୯ ᶅ DOM΋StateͰ͍࣋ͬͯΔͷͰɺJSΦϒδΣΫτͰ؅ཧͰ͖Δʢେ੾ʣ ߋʹɺReactίϯϙʔωϯτͰϦονͳදࣔ΋Ͱ͖Δɻ Draft.jsͷ࠾༻

Slide 7

Slide 7 text

γΰτͰίίϩΦυϧ ී௨ͷinputλά class MyInput extends React.Component { constructor(props) { super(props); this.state = {value: ''}; this.onChange = (e) => this.setState({value: e.target.value}); } render() { return ; } }

Slide 8

Slide 8 text

γΰτͰίίϩΦυϧ Draft.jsͰ؅ཧ͢Δ৔߹ import React from ‘react’; import {Editor, EditorState} from 'draft-js'; class MyEditor extends React.Component { constructor(props) { super(props); this.state = {editorState: EditorState.createEmpty()}; this.onChange = (editorState) => this.setState({editorState}); } render() { return ; } } EditorͷComponent Editorͷঢ়ଶΛද͢State input, textAreaͱಉ͡ײ֮Ͱ࢖͑Δ!͜ΕΛ֦ு͍ͯ͘͠

Slide 9

Slide 9 text

γΰτͰίίϩΦυϧ Block Block [{ depth: 0, entityRanges: [], inlineStyleRanges: [], key: "67fie", text: "ݟग़͠", type: "header-two" },{ depth: 0, entityRanges: [], inlineStyleRanges: [], key: "67fie", text: "ී௨ͷςΩετ", type: "unstyled" }] ݟग़͠ Preview ී௨ͷςΩετ typeΛม͑Δ͜ͱͰ ରԠ͢Δཁૉʹม͑Δ͜ͱ ͕Ͱ͖Δ (ex. h1..h6, blockquote, code)

Slide 10

Slide 10 text

γΰτͰίίϩΦυϧ InlineStyle Block { depth: 0, entityRanges: [], inlineStyleRanges: [ { length: 2 offset: 0 style: “BOLD” } ], key: "67fie", text: "ଠࣈʹͳΔ", type: "header-two" } InlineStyle ଠࣈʹͳΔ Preview StyleΛม͑Δ͜ͱͰ ରԠ͢ΔελΠϧΛ౰ͯΔ ͜ͱ͕Ͱ͖Δɻ (ex. BOLD, ITALIC, UNDERLINE)

Slide 11

Slide 11 text

γΰτͰίίϩΦυϧ Entity Block { depth: 0, entityRanges: [ { key: 0, length: 3, offset: 0 } ], inlineStyleRanges: [], key: "67fie", text: "ϦϯΫʹͳΔ", type: "unstyled" } entityMap: { 0: { data: { url: “http://wantedly.com“
 }, mutability: “MUTABLE”, type: “LINK”, }
 } Entity Entity ϦϯΫʹͳΔ Preview จࣈɺ૷০Ҏ֎ͷ৘ใ͸ EntityͰ؅ཧΛߦ͏ɻ

Slide 12

Slide 12 text

γΰτͰίίϩΦυϧ DOM௚઀͞ΘΓͨ͘ͳ͍໰୊ ղܾʂ ͍͍ײ͡ʹ৮Γ΍͍͢API͕ఏڙ͞Ε͍ͯΔͷͰ ޙ͸Block΍InlineStyle, EntityΛ͍͡Δ͚ͩͰྑ͍ɻ

Slide 13

Slide 13 text

γΰτͰίίϩΦυϧ Custom Block Compoent ReactComponentΛ࢖ͬͨϦον ͳίϯϙʔωϯτ͕࡞ΕΔɻ Ԡ༻͢ΔͱɺEntityͷσʔλΛߋ ৽ͯ͠ΠϯλϥΫςΟϒͳײ͡ͷ ΋ͷΛ࡞ΕΔɻ data: { created_at : "2016-06-21T16:29:55.9 id: 10 provider_name: "Wantedly" thumbnail: “https://d2v9k5u4v94ulw title: "Ϟμϯͳ؀ڥͰReactΛॻ͖͍ͨ type: “link" updated_at: "2016-06-21T16:29:55.9 url: "https://www.wantedly.com/pro }, mutability: “IMMUTABLE", type: "EMBED" Preview Entity

Slide 14

Slide 14 text

γΰτͰίίϩΦυϧ HTML΁ͷม׵ • GithubʹDraft.jsͷσʔλܗ͔ࣜΒHTML΍ASTʹม׵͢ ΔϥΠϒϥϦ͕ز͔ͭެ։͞Ε͍ͯΔɻ • WantedlyͰ͸RubyͰDraft.jsͷσʔλܗ͔ࣜΒHTMLʹ ม׵͢ΔίʔυΛॻ͍ͯରԠ͍ͯ͠Δɻ • iOS͕ωΠςΟϒΞϓϦͰهࣄΛදࣔ͢ΔํࣜΛ࠾༻ͯ͠ ͓Γɺ΄΅Draft.jsͷσʔλܗࣜʹἧ͍͑ͯΔɻ

Slide 15

Slide 15 text

γΰτͰίίϩΦυϧ Draft.jsͷਏ͍ͱ͜Ζ • ೔ຊʹ͋·Γ࢖͍ͬͯΔਓ͕͍ͳ͍ͷͰӳޠΛಡΉ͜ͱʹ ͳΔɻ • ࡉ͔͍ௐ੔Λ͢Δͱ͖ʹdraft.jsຊମͷίʔυಡΉඞཁ͕ ͋Δɻ • ϚϧνόΠτจࣈݻ༗ͷਏ͍ڍಈ͕͋Δɻ • ݁ہΩϟϨοτͷൣғ؅ཧͷਏ͞͸࢒Δɻ • σϑΥϧτͷվߦͷڍಈ͕޷ΈͰͳͯ݁͘ߏ͍ͬͨ͡ɻ

Slide 16

Slide 16 text

γΰτͰίίϩΦυϧ ಋೖͯ͠Έͨײ૝ • Draft.jsΛಋೖ͢Δ͜ͱͰɺ։ൃָ͕ʹͳΔ ͭΒ͍ͱ͜Ζ͸͋Δ͚Ͳɺࠓ·ͰΑΓ͸͔ͳΓָɻ ։ൃָ͕ʹͳͬͨ෼ɺϢʔβʔ΋؆୯ʹهࣄΛ࡞ΕΔΑ͏ ʹ͍͖͍ͯͨ͠ɻ

Slide 17

Slide 17 text

γΰτͰίίϩΦυϧ ࠷ޙʹ

Slide 18

Slide 18 text

Wantedly FeedͰ ΤϯδχΞϒϩάΛॻ͖·͠ΐ͏ʂ ࠾༻ʹܨ͕ΔʮWantedly͔ͩΒͦ͜ʯͷՁ஋Λఏڙ͠·͢