Meguro.es #4 @wantedlyでのトーク内容です
React.js, Draft.jsͰ࡞ΔϦονςΩετΤσΟλ։ൃೖMeguro.es #4 @Wantedlyຊ ༤و (@mottox2)
View Slide
γΰτͰίίϩΦυϧࣗݾհຊ ༤و @mottox2• Wantedly৽ଔҰͷΤϯδχΞ• ϑϩϯτΤϯυ͕͖• ʮϑΟʔυʯΛ࡞͍ͬͯ·͢
දݱͷ෯Λ͛ΔͨΊʹϒϩάΤσΟλͷϦχϡʔΞϧΛߦͬͨ
γΰτͰίίϩΦυϧϦονςΩετΤσΟλ։ൃϦονςΩετΤσΟλͷඞཁੑΤϯδχΞք۾ͰϚʔΫμϯʴϓϨϏϡʔ͕ྲྀߦ͍ͬͯΔɻී௨ͷਓ͔Βͨ͠ΒϦονςΩετΤσΟλ͕ͨΓલɻʮฤू͍ͯ͠Δݟͨʹެ։͞ΕΔͷʯͰ͋ͬͯཉ͍ͣ͠ɻϦονςΩετΤσΟλ։ൃͷਏ͞(=contenteditableͱͷઓ͍)ᶃ ϒϥβʹΑͬͯڍಈ͕ҧ͏ᶄ ཤྺཧ͕େมᶅ DOMΛ৮Δඞཁ͕͋Δ
γΰτͰίίϩΦυϧ͜Ε·ͰҎલͷΤσΟλReact+ReduxߏͷதͰɺੜͷDOMΛ͍͍ͬͯͨ͡ɻ֦ுͣ͠Β͍DOMΛ৮ͬͯཧ͍ͯ͠Δ෦
γΰτͰίίϩΦυϧDraft.jsͱʁFacebookͷެ։͍ͯ͠ΔOSSɻReact.js্ͰϦονςΩετΤσΟλΛߏங͢ΔͨΊͷίϯϙʔωϯτΛఏڙͯ͘͠ΕΔɻhttps://github.com/facebook/draft-jsԸܙᶃ ϒϥβؒͷڍಈͷࠩΛٵऩͯ͘͠ΕΔɻᶄ ΤσΟλશମΛ1ͭͷStateͱͯ͠ཧ͢Δ͔Βɺཤྺཧ؆୯ᶅ DOMStateͰ͍࣋ͬͯΔͷͰɺJSΦϒδΣΫτͰཧͰ͖ΔʢେʣߋʹɺReactίϯϙʔωϯτͰϦονͳදࣔͰ͖ΔɻDraft.jsͷ࠾༻
γΰτͰίίϩΦυϧී௨ͷinputλάclass MyInput extends React.Component {constructor(props) {super(props);this.state = {value: ''};this.onChange = (e) => this.setState({value: e.target.value});}render() {return ;}}
γΰτͰίίϩΦυϧ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 onChange={this.onChange} />;}} EditorͷComponentEditorͷঢ়ଶΛද͢Stateinput, textAreaͱಉ͡ײ֮Ͱ͑Δ!͜ΕΛ֦ு͍ͯ͘͠
γΰτͰίίϩΦυϧBlockBlock[{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)
γΰτͰίίϩΦυϧInlineStyleBlock{depth: 0,entityRanges: [],inlineStyleRanges: [{length: 2offset: 0style: “BOLD”}],key: "67fie",text: "ଠࣈʹͳΔ",type: "header-two"}InlineStyleଠࣈʹͳΔPreviewStyleΛม͑Δ͜ͱͰରԠ͢ΔελΠϧΛͯΔ͜ͱ͕Ͱ͖Δɻ(ex. BOLD, ITALIC, UNDERLINE)
γΰτͰίίϩΦυϧEntityBlock{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”,} }EntityEntityϦϯΫʹͳΔPreviewจࣈɺ০Ҏ֎ͷใEntityͰཧΛߦ͏ɻ
γΰτͰίίϩΦυϧDOM͞ΘΓͨ͘ͳ͍ղܾʂ͍͍ײ͡ʹ৮Γ͍͢API͕ఏڙ͞Ε͍ͯΔͷͰޙBlockInlineStyle, EntityΛ͍͡Δ͚ͩͰྑ͍ɻ
γΰτͰίίϩΦυϧCustom Block CompoentReactComponentΛͬͨϦονͳίϯϙʔωϯτ͕࡞ΕΔɻԠ༻͢ΔͱɺEntityͷσʔλΛߋ৽ͯ͠ΠϯλϥΫςΟϒͳײ͡ͷͷΛ࡞ΕΔɻdata: {created_at : "2016-06-21T16:29:55.9id: 10provider_name: "Wantedly"thumbnail: “https://d2v9k5u4v94ulwtitle: "ϞμϯͳڥͰReactΛॻ͖͍ͨtype: “link"updated_at: "2016-06-21T16:29:55.9url: "https://www.wantedly.com/pro},mutability: “IMMUTABLE",type: "EMBED"PreviewEntity
γΰτͰίίϩΦυϧHTMLͷม• GithubʹDraft.jsͷσʔλܗ͔ࣜΒHTMLASTʹม͢ΔϥΠϒϥϦ͕ز͔ͭެ։͞Ε͍ͯΔɻ• WantedlyͰRubyͰDraft.jsͷσʔλܗ͔ࣜΒHTMLʹม͢ΔίʔυΛॻ͍ͯରԠ͍ͯ͠Δɻ• iOS͕ωΠςΟϒΞϓϦͰهࣄΛදࣔ͢ΔํࣜΛ࠾༻͓ͯ͠Γɺ΄΅Draft.jsͷσʔλܗࣜʹἧ͍͑ͯΔɻ
γΰτͰίίϩΦυϧDraft.jsͷਏ͍ͱ͜Ζ• ຊʹ͋·Γ͍ͬͯΔਓ͕͍ͳ͍ͷͰӳޠΛಡΉ͜ͱʹͳΔɻ• ࡉ͔͍ௐΛ͢Δͱ͖ʹdraft.jsຊମͷίʔυಡΉඞཁ͕͋Δɻ• ϚϧνόΠτจࣈݻ༗ͷਏ͍ڍಈ͕͋Δɻ• ݁ہΩϟϨοτͷൣғཧͷਏ͞Δɻ• σϑΥϧτͷվߦͷڍಈ͕ΈͰͳͯ݁͘ߏ͍ͬͨ͡ɻ
γΰτͰίίϩΦυϧಋೖͯ͠Έͨײ• Draft.jsΛಋೖ͢Δ͜ͱͰɺ։ൃָ͕ʹͳΔͭΒ͍ͱ͜Ζ͋Δ͚Ͳɺࠓ·ͰΑΓ͔ͳΓָɻ։ൃָ͕ʹͳͬͨɺϢʔβʔ؆୯ʹهࣄΛ࡞ΕΔΑ͏ʹ͍͖͍ͯͨ͠ɻ
γΰτͰίίϩΦυϧ࠷ޙʹ
Wantedly FeedͰΤϯδχΞϒϩάΛॻ͖·͠ΐ͏ʂ࠾༻ʹܨ͕ΔʮWantedly͔ͩΒͦ͜ʯͷՁΛఏڙ͠·͢