Slide 1

Slide 1 text

Eight メンション機能の フロントエンド実装 DSOC Development Group ΤϯδχΞ ໦ా༔Ұ࿠ プラットフォームサービスの成⻑を⽀える技術〜 Web現場Meetup #4 2018/10/22

Slide 2

Slide 2 text

⾃⼰紹介

Slide 3

Slide 3 text

プロフィール • 名前 : ⽊⽥ 悠⼀郎 • 趣味 : テニス、個⼈開発、ブログ • Twitter : @mokuo_ • GitHub : mokuo • Qiita : @mokuo • 個⼈ブログ : blog.mokuo.me

Slide 4

Slide 4 text

経歴 • SIer, Rails 受託開発会社などを経験 • 2018年2⽉ Sansan ⼊社 Eight 事業部配属 • Rails エンジニアとして⼊社したが、気づくと React を書いていた • メンション機能のWebフロントエンド実装を担当 • 2018年6⽉ DSOC に異動 • Rails エンジニアに戻る • GEES(名刺データ化システム)の開発・運⽤をやっています

Slide 5

Slide 5 text

DSOC について 5 • Data Strategy & Operation Center • 「データ⽣成から活⽤へ」 • 名刺のデータ化 • 新たな価値 参照 : https://jp.corp-sansan.com/dsoc/about.html

Slide 6

Slide 6 text

アジェンダ

Slide 7

Slide 7 text

アジェンダ - Eight 開発環境 - Eight メンション機能とは - Eight メンション機能の設計 - Eight メンション機能のサーバーサイド - Eight メンション機能のフロントエンド - 使⽤ライブラリ - Eight における実装

Slide 8

Slide 8 text

Eight 開発環境 8

Slide 9

Slide 9 text

Eight 開発環境 - サーバーサイド - Ruby on Rails - フロントエンド - React + Redux - インフラ - AWS

Slide 10

Slide 10 text

Eight メンション機能とは 10

Slide 11

Slide 11 text

Eight メンション機能とは - 投稿をするとき、特定の相⼿をメンションする – Eight ヘルプ 11 ౤ߘྫ ίϝϯτྫ

Slide 12

Slide 12 text

メンション機能の設計 12

Slide 13

Slide 13 text

メンション機能の設計 - 設計にあたり、他サービスを調査 13

Slide 14

Slide 14 text

Twitter - Twitter API ドキュメント - メンション位置情報を保持 14 [ { "text": "@jasoncosta @themattharris Hey! Going to be in Frisco in October. Was hoping to have a meeting to talk about @thinkwall if you're around?", "mentions": [ { "user_name": "Jason Costa", ”user_id": 14927800, "indices": [0, 11], "screen_name": "jasoncosta” }, { "user_name": "Matt Harris", "user_id": 777925, "indices": [12, 26], "screen_name": "themattharris” }, { "user_name": "ThinkWall", "user_id": 117426578, "indices": [109, 119], "screen_name": "thinkwall” } ] } ] @jasoncosta @themattharris Hey! Going to be in Frisco in October. Was hoping to have a meeting to talk about @thinkwall if you're around?", දࣔ͢Δࡍʹ૷০

Slide 15

Slide 15 text

Twitter ⽅式のメリット・デメリット - メリット - テキストを置換する必要がない - デメリット - 投稿を更新する際にメンション位置も更新する必要がある 15

Slide 16

Slide 16 text

Slack - Slack API ドキュメント - メンション部分をプレースホルダーとして 保持 16 [ { "text": " Hey <@U024BE7LH>, did you see my file? ", "mentions": [ { ”user_name": "Jason Costa", ”user_id": 024BE7LH, "screen_name": "jasoncosta” }, ] } ] Hey @jasoncosta, did you see my file? දࣔ͢Δࡍʹஔ׵

Slide 17

Slide 17 text

Slack ⽅式のメリット・デメリット - メリット - メンション位置を更新する必要がない - デメリット - メンション部分を テキスト <=> プレースホルダ で変換・逆変換する必要があ る 17 @jasoncosta ó <@U024BE7LH>

Slide 18

Slide 18 text

Eight はどうしたか - 投稿を編集できる場合、メンション位置を更新し続けるのは⼤変 - Twitter は投稿を編集できないので、メンション位置を更新する必要がない - プレースホルダーが適していると判断 18

Slide 19

Slide 19 text

Eight メンション機能のサーバーサイド 19

Slide 20

Slide 20 text

テーブル定義(イメージ) 20 users - id - name - … posts - id - content - … mentions - id - user_id - post_id

Slide 21

Slide 21 text

Eight メンション機能のフロントエンド 21

Slide 22

Slide 22 text

使⽤ライブラリ 22

Slide 23

Slide 23 text

メンション機能に使⽤したライブラリ - Draft.js - DraftJS Plugins 23

Slide 24

Slide 24 text

Draft.js とは - React 向けリッチテキストエディタ - 引⽤、箇条書き、コードブロック、太字・・・etc - Facebook 製 - https://draftjs.org/ 24

Slide 25

Slide 25 text

DraftJS Plugins とは - Draft.js のプラグイン - 絵⽂字、メンション、ハッシュタグ・・・etc - https://www.draft-js-plugins.com/ 25

Slide 26

Slide 26 text

Draft.js の概念 - 主な登場⼈物は5⼈ - EditorState - ContentState - ContentBlock - CharacterMetadata - Entity - 実態は Immutable.js の Record 26

Slide 27

Slide 27 text

Entity について - 引⽤、太字、メンションなどをを Entity という概念で扱う。 - CharacterMetadata (1⽂字)ごとに entity を持っていて、1以上の数値か null が⼊る。 - 例)⼭⽥太郎 さん - `entity: 1` => メンション 27 editorState.getCurrentContent().getBlockMap().first() .getCharacterList().toJS() => [ {style: [], entity: "1"}, #⼭ {style: [], entity: "1"}, #⽥ {style: [], entity: "1"}, #太 {style: [], entity: "1"}, #郎 {style: [], entity: null}, #さ {style: [], entity: null}, #ん ]

Slide 28

Slide 28 text

Draft.js と仲良くなるために - Create React App に Draft.js を⼊れて動作検証 28

Slide 29

Slide 29 text

Eight における実装 29

Slide 30

Slide 30 text

実装例 : フィードにメンションを表⽰する 1. サーバーから投稿⽂とメンション情報を取得 2. 投稿⽂をプレーンテキスト、メンション、URLに分類 - オブジェクトの配列を⽣成 3. 表⽰ - 2. で作った配列をコンポーネントに渡す 30

Slide 31

Slide 31 text

オブジェクトの配列を⽣成するイメージ 31 # 実際には、text と mentions はサーバーから送られてきます const text = ‘<@p[123456]> さん、URLはhttps://example.comです。'; const mentions = fromJS([ { mentionId: 1, user: { id: 123456, name: '⼭⽥ 太郎', }, } ]); const objects = convertToObjects(text, mentions); => [ { type: 'mention', props: { href: '/users/123456' }, body: '⼭⽥ 太郎' }, { type: 'plainText', body: ' さん、URLは' }, { type: 'url' , props: { href: 'https://example.com' }, body: 'https://example.com' }, { type: 'plainText', body: 'です。' } ];

Slide 32

Slide 32 text

表⽰部分のイメージ ⼭⽥太郎 さん、URLは https://example.com です。 32 => ⼭⽥ 太郎 さん、URLは https://example.com です。

Slide 33

Slide 33 text

他にも、以下のような機能を実装 - 新規投稿でメンションできる - 投稿編集でメンションを追加・削除できる - コメントでも投稿と同様にメンションできる - コメント返信でメンションされる - ⾏動ログの取得 - アプリ通知 33

Slide 34

Slide 34 text

反省点 - Slack ⽅式ではなく Twitter ⽅式の⽅がシンプルに実装できたかもしれない - Twitter ⽅式 : メンション位置情報を保持 - Slack ⽅式 : プレースホルダーに置換 - 正規表現で毎回置換するのが⼤変 - Draft.js が位置情報を持ってくれていた 34

Slide 35

Slide 35 text

ご清聴ありがとうございました。 35