[React]Slack風の絵文字ライブラリEmojiMartの使い方

- この記事は[React #2 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/react2)の16日目の記事です(体調崩していたため遅くなってしまいました。すみません。。)

## 概要

- Slackなどでよく見かけるこのような絵文字は皆さんご存知かと思います

<img width="379" alt="スクリーンショット 2019-12-09 23.24.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/d340015c-9b53-c2a8-b3d3-e71b8e9d1c1c.png">

- これを自分の開発するReactアプリに取り入れたくて調べてみたところ[Emoji Mart](https://github.com/missive/emoji-mart)というライブラリがありました
- 日本語で使い方を説明する記事がほとんどなかったので紹介したいと思います
- ちなみにEmoji Mart以外だと[emoji-picker-react](https://github.com/ealush/emoji-picker-react)というのもあって、Qiitaの絵文字はコードを見た感じこちらが使われているようです

## セットアップ

- npmのライブラリとして公開されているので`npm install`でインストールします

```bash
npm i emoji-mart
# or
yarn add emoji-mart
```

- これで準備OK

## コンポーネント

- Emoji Martでは`<Picker />`と`<Emoji />`の2つのコンポーネントが提供されています
- Pickerは絵文字を選択するUIを表示するコンポーネントです
<img width="345" alt="スクリーンショット 2019-12-09 23.30.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/30686f08-ccdf-1922-86f2-87bc15fb9c05.png">

- Emojiは個々の絵文字を表示するコンポーネントです
<img width="28" alt="スクリーンショット 2019-12-09 23.30.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/dc3373e2-ba1e-6608-b721-fcdc6dd08771.png">

- それぞれもう少し詳細まで見てみます

### Picker

```jsx
import { Picker } from 'emoji-mart';
import 'emoji-mart/css/emoji-mart.css';
```

- 使う際はcssとセットでimportします
- [公式のREADME](https://github.com/missive/emoji-mart#picker)を見るとPickerコンポーネントは30ほどのpropsを受け付けます
- 細かい所の調整がいろいろできるだけなので重要どころだけピックアップします

#### onSelect

```jsx
<Picker onSelect={emoji => alert(JSON.stringify(emoji))} />
```

<img width="616" alt="スクリーンショット 2019-12-19 23.14.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/dcd9cc6e-ffdb-418a-bc30-9a36bbeabd64.png">

- `onSelect`は絵文字を選択したときに呼ばれる関数です
- 引数で選択した絵文字の情報を受け取れます（上記キャプチャ参照）
- `id`の値をサーバへ送信することになるでしょう

#### set/native

```jsx
<Picker onSelect={emoji => alert(JSON.stringify(emoji))} set="google" />
```

- 絵文字の種類を変えることができます
- `set`には'apple', 'google', 'twitter', 'emojione', 'messenger', 'facebook'のいずれかを設定することができます（defaultはapple）
- それぞれの見た目の違いは[公式のサンプル](https://missive.github.io/emoji-mart/)でチェックできます
<img width="385" alt="スクリーンショット 2019-12-19 23.24.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/4c7c3752-22fb-d1ae-c072-db8f6a60febe.png">

```jsx
<Picker onSelect={emoji => alert(JSON.stringify(emoji))} native />
```

- `native`を渡すと`set`の値は無視されunicodeの絵文字が使用されます
- `set`で指定する絵文字は画像を使っていて通信処理が発生するため`native`の方が表示速度は早くなります

<img width="342" alt="スクリーンショット 2019-12-19 23.28.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/91d4eb55-5591-50a7-2715-9840cc38d3fc.png">

#### i18n

```jsx
<Picker
  i18n={{
    search: '検索',
    categories: {
      search: '検索結果',
      recent: 'よく使う絵文字',
      people: '顔 & 人',
      nature: '動物 & 自然',
      foods: '食べ物 & 飲み物',
      activity: 'アクティビティ',
      places: '旅行 & 場所',
      objects: 'オブジェクト',
      symbols: '記号',
      flags: '旗',
      custom: 'カスタム',
    },
  }}
/>
```

<img width="339" alt="スクリーンショット 2019-12-19 23.31.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/11f411bf-fb9b-6044-0685-cf842d741dee.png">

- 絵文字のカテゴリなどを日本語化できます

### Emoji

```jsx
import { Emoji } from 'emoji-mart';
```

- [公式のREADME](https://github.com/missive/emoji-mart#emoji)を見るとEmojiコンポーネントの方は13のpropsを受け付けます
- ぱっと見て用途が想像つきやすいものばかりなのでそれほどややこしくないです

#### emoji/size

```jsx
<Emoji emoji="thinking_face" size={64} />
```

<img width="77" alt="スクリーンショット 2019-12-19 23.48.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/4995386f-4d67-65d0-5826-27ecb14f6ad4.png">

- `emoji`と`size`の2つが必須項目です
- `emoji`は`Picker`の`onSelect`のところで登場した`id`に当たる値を入れればOKです
- `size`は単純に大きさを指定します

#### onClick

```jsx
<Emoji emoji="thinking_face" size={64} onClick={emoji => alert(JSON.stringify(emoji))} />
```

<img width="552" alt="スクリーンショット 2019-12-19 23.52.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/65c1955a-db42-a6af-dcdc-823cfe31f612.png">

- 絵文字をクリックしたときに呼ばれる関数です
- `Picker`の`onSelect`と同じ用に絵文字の情報を取得できます
- 誰かが押した絵文字をクリックすると自分も押したことになる、なんて挙動をするアプリがよくありますよね
- そんな実装をするときに便利そうです

#### set/native

- こちらは`Picker`での説明と全く同様です

## サンプル

- 簡単ではありますが動くコードも載せておきます
- create-react-appしてApp.jsをこれに書き換えたら動くはずです
- https://react-emoji-sample.netlify.com/

![demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/d17def01-77d9-1567-2666-886779ced91d.gif)

```jsx:App.js
import React, { useState } from 'react';
import { Emoji, Picker } from 'emoji-mart';
import 'emoji-mart/css/emoji-mart.css';

const emojiTypeList = [
  'apple',
  'google',
  'twitter',
  'emojione',
  'messenger',
  'facebook',
];

function App() {
  const [emojiList, setEmojiList] = useState([]);
  const [emojiType, setEmojiType] = useState(null);

  const onClickButton = e => {
    setEmojiType(e.target.name);
  };

  const onSelect = emoji => {
    console.log({ emoji });
    setEmojiList([...emojiList, emoji]);
    setEmojiType(null);
  };
  return (
    <>
      <p>
        {emojiTypeList.map(name => (
          <button onClick={onClickButton} name={name} key={name}>
            {name}
          </button>
        ))}
      </p>
      {emojiType && (
        <Picker
          onSelect={emoji => onSelect({ ...emoji, emojiType })}
          set={emojiType}
          i18n={{
            search: '検索',
            categories: {
              search: '検索結果',
              recent: 'よく使う絵文字',
              people: '顔 & 人',
              nature: '動物 & 自然',
              foods: '食べ物 & 飲み物',
              activity: 'アクティビティ',
              places: '旅行 & 場所',
              objects: 'オブジェクト',
              symbols: '記号',
              flags: '旗',
              custom: 'カスタム',
            },
          }}
          style={{
            position: 'absolute',
            zIndex: '1',
          }}
        />
      )}
      {emojiList.length
        ? emojiList.map(({ id, emojiType }, i) => (
            <Emoji
              emoji={id}
              size={32}
              set={emojiType}
              onClick={emoji => onSelect({ ...emoji, emojiType })}
              key={i}
            />
          ))
        : null}
    </>
  );
}

export default App;
```

## まとめ

- Emoji Martを使うとそれほど苦労することなくSlack風絵文字をアプリに入れることができました
- READMEを最初に見たときはpropsの多さに身構えてしまいましたが、ちゃんとドキュメントを読んで手を動かせば理解することができました