Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
React.js, Draft.jsで作る リッチテキストエディタ開発入門
Search
mottox2
June 21, 2016
Programming
14
15k
React.js, Draft.jsで作る リッチテキストエディタ開発入門
Meguro.es #4 @wantedlyでのトーク内容です
mottox2
June 21, 2016
Tweet
Share
More Decks by mottox2
See All by mottox2
もう一歩進めたい OG画像の動的生成
mottox2
7
1.7k
なぜコピペで使うコンポーネント集を利用するのか?
mottox2
8
7k
UIコンポーネントライブラリをうまく使うためにできること / components-with-designer
mottox2
7
3.8k
Figma Plugin公開までの壁を乗り越える
mottox2
2
3.2k
Puppeteerでつくる画像と動画 / images and videos made with puppeteer
mottox2
0
660
手触りのよいウェブを考える / better-mobile-web
mottox2
3
1.8k
組織と権限とSlack App / slack-app-with-roles
mottox2
1
640
SSRを避けるためにやっていること / ssr-alternative
mottox2
9
3.2k
JSXでつくる宣言的UIなプレゼンテーション / jsx-presentation
mottox2
7
33k
Other Decks in Programming
See All in Programming
Youtube Lofier - Chrome拡張開発
ninikoko
0
2.5k
監視 やばい
syossan27
11
10k
ComposeでのPicture in Picture
takathemax
0
120
Building Scalable Mobile Projects: Fast Builds, High Reusability and Clear Ownership
cyrilmottier
2
310
エンジニアが挑む、限界までの越境
nealle
1
280
KawaiiLT 登壇資料 キャリアとモチベーション
hiiragi
0
150
Compose Hot Reload is here, stop re-launching your apps! (Android Makers 2025)
zsmb
1
550
Make Parsers Compatible Using Automata Learning
makenowjust
2
5.6k
AWS で実現する安全な AI エージェントの作り方 〜 Bedrock Engineer の実装例を添えて 〜 / how-to-build-secure-ai-agents
gawa
8
870
これだけは知っておきたいクラス設計の基礎知識 version 2
masuda220
PRO
24
6.6k
Golangci-lint v2爆誕: 君たちはどうすべきか
logica0419
1
160
設計の本質:コード、システム、そして組織へ / The Essence of Design: To Code, Systems, and Organizations
nrslib
7
1.7k
Featured
See All Featured
Why Our Code Smells
bkeepers
PRO
336
57k
Scaling GitHub
holman
459
140k
Bash Introduction
62gerente
611
210k
How to train your dragon (web standard)
notwaldorf
90
6k
Music & Morning Musume
bryan
47
6.5k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
13
1.4k
Testing 201, or: Great Expectations
jmmastey
42
7.5k
Designing for humans not robots
tammielis
253
25k
Fireside Chat
paigeccino
37
3.4k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
Measuring & Analyzing Core Web Vitals
bluesmoon
7
400
Git: the NoSQL Database
bkeepers
PRO
430
65k
Transcript
React.js, Draft.jsͰ࡞Δ ϦονςΩετΤσΟλ։ൃೖ Meguro.es #4 @Wantedly ຊ ༤و (@mottox2)
γΰτͰίίϩΦυϧ ࣗݾհ ຊ ༤و @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 <input value={this.state.value} onChange={this.onChange} />; } }
γΰτͰίίϩΦυϧ 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 editorState={this.state.editorState} onChange={this.onChange} />; } } EditorͷComponent Editorͷঢ়ଶΛද͢State input, textAreaͱಉ͡ײ֮Ͱ͑Δ!͜ΕΛ֦ு͍ͯ͘͠
γΰτͰίίϩΦυϧ 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)
γΰτͰίίϩΦυϧ 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)
γΰτͰίίϩΦυϧ 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ͰཧΛߦ͏ɻ
γΰτͰίίϩΦυϧ DOM͞ΘΓͨ͘ͳ͍ ղܾʂ ͍͍ײ͡ʹ৮Γ͍͢API͕ఏڙ͞Ε͍ͯΔͷͰ ޙBlockInlineStyle, EntityΛ͍͡Δ͚ͩͰྑ͍ɻ
γΰτͰίίϩΦυϧ 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
γΰτͰίίϩΦυϧ HTMLͷม • GithubʹDraft.jsͷσʔλܗ͔ࣜΒHTMLASTʹม͢ ΔϥΠϒϥϦ͕ز͔ͭެ։͞Ε͍ͯΔɻ • WantedlyͰRubyͰDraft.jsͷσʔλܗ͔ࣜΒHTMLʹ ม͢ΔίʔυΛॻ͍ͯରԠ͍ͯ͠Δɻ • iOS͕ωΠςΟϒΞϓϦͰهࣄΛදࣔ͢ΔํࣜΛ࠾༻ͯ͠
͓Γɺ΄΅Draft.jsͷσʔλܗࣜʹἧ͍͑ͯΔɻ
γΰτͰίίϩΦυϧ Draft.jsͷਏ͍ͱ͜Ζ • ຊʹ͋·Γ͍ͬͯΔਓ͕͍ͳ͍ͷͰӳޠΛಡΉ͜ͱʹ ͳΔɻ • ࡉ͔͍ௐΛ͢Δͱ͖ʹdraft.jsຊମͷίʔυಡΉඞཁ͕ ͋Δɻ • ϚϧνόΠτจࣈݻ༗ͷਏ͍ڍಈ͕͋Δɻ
• ݁ہΩϟϨοτͷൣғཧͷਏ͞Δɻ • σϑΥϧτͷվߦͷڍಈ͕ΈͰͳͯ݁͘ߏ͍ͬͨ͡ɻ
γΰτͰίίϩΦυϧ ಋೖͯ͠Έͨײ • Draft.jsΛಋೖ͢Δ͜ͱͰɺ։ൃָ͕ʹͳΔ ͭΒ͍ͱ͜Ζ͋Δ͚Ͳɺࠓ·ͰΑΓ͔ͳΓָɻ ։ൃָ͕ʹͳͬͨɺϢʔβʔ؆୯ʹهࣄΛ࡞ΕΔΑ͏ ʹ͍͖͍ͯͨ͠ɻ
γΰτͰίίϩΦυϧ ࠷ޙʹ
Wantedly FeedͰ ΤϯδχΞϒϩάΛॻ͖·͠ΐ͏ʂ ࠾༻ʹܨ͕ΔʮWantedly͔ͩΒͦ͜ʯͷՁΛఏڙ͠·͢