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
15k
14
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
React.js, Draft.jsで作る リッチテキストエディタ開発入門
Meguro.es #4 @wantedlyでのトーク内容です
mottox2
June 21, 2016
More Decks by mottox2
See All by mottox2
つくり方を変えていく | change-how-we-build
mottox2
2
1.4k
もう一歩進めたい OG画像の動的生成
mottox2
7
2.8k
なぜコピペで使うコンポーネント集を利用するのか?
mottox2
8
7.6k
UIコンポーネントライブラリをうまく使うためにできること / components-with-designer
mottox2
7
4.1k
Figma Plugin公開までの壁を乗り越える
mottox2
3
4.2k
Puppeteerでつくる画像と動画 / images and videos made with puppeteer
mottox2
0
790
手触りのよいウェブを考える / better-mobile-web
mottox2
3
2.1k
組織と権限とSlack App / slack-app-with-roles
mottox2
1
740
SSRを避けるためにやっていること / ssr-alternative
mottox2
9
3.3k
Other Decks in Programming
See All in Programming
2年かけて Deno に DOMMatrix を実装した話 / How I implemented DOMMatrix in Deno over two years
petamoriken
0
210
freeeにおけるEvalsの実践例の紹介
freee
PRO
0
130
夏だ!祭りだ!祭りとはドメインモデリングでは?
ryugen04
0
340
片田舎のおっさん、 Swift Buildのダイアモンド問題解決の不具合修正PRを出すが、解決方法がキャッシュをしないようにすることであり、ビルド時間が伸びると言われてマージされないので高速化もする/swiftbuild
yimajo
0
210
KotlinConf Extended South Korea 2026 Keynote
l2hyunwoo
0
110
in-process GraphQL のすすめ #ginzajs
izumin5210
4
1.4k
Oxlintはいいぞ(続)
yug1224
1
260
使いながら育てる Claude Code — 開発フローの1コマンド化 × 繰り返し指摘の自動仕組み化
shiki_kakaku
0
1.9k
複数の Claude Code が"放置"されてしまう問題をCLI ダッシュボードを自作して解決した話
sumihiro3
1
710
Cloudflare is Agents
chimame
0
170
30年振りにコンパイラの定数整数除算を改善した
herumi
1
450
メールのエイリアス機能を履き違えない
isshinfunada
0
250
Featured
See All Featured
Exploring anti-patterns in Rails
aemeredith
3
470
Leo the Paperboy
mayatellez
8
2.2k
Typedesign – Prime Four
hannesfritz
42
3.1k
HTML-Aware ERB: The Path to Reactive Rendering @ RubyCon 2026, Rimini, Italy
marcoroth
3
460
Odyssey Design
rkendrick25
PRO
2
770
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
680
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
63
45k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
38
3k
GitHub's CSS Performance
jonrohan
1033
470k
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
1
250
From π to Pie charts
rasagy
0
310
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.6k
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͔ͩΒͦ͜ʯͷՁΛఏڙ͠·͢