ワイ「アニメーションするにはこのuseTransitionってのを使えばええんか？」

社長「[やめ太郎くん](https://qiita.com/Yametaro)」

ワイ「なんでっか社長、ワイは今**Reactのアプリを半分だけVueに書き換える作業**で忙しいんでっせ」

[ハスケル子](https://qiita.com/Yametaro/items/11dcd3ec26027ff30214)「（何でそんな意味不明なことを……）」

社長「せやったな、[これからはVueの時代](https://yumemi.connpass.com/event/157720/)やからVueの使用実績を増やさなあかんねん」

ワイ「とはいえReactも今年公式ドキュメントの日本語版が出たり勢いづいとるから捨てがたい」

社長「せやから半々にしてどっちも取り入れるんや！　素晴らしい施策やろ！」

ワイ「さすが社長！」

ハリー先輩「（案件を半々にするんちゃうのかい！）」

ハスケル子「（私は何でこんな所でインターンしているんだろう）」

※ この記事は全面**[無職やめ太郎さん](https://qiita.com/Yametaro)リスペクト**の**ワイ記法**でお送りする二次創作記事です。（[6ヶ月ぶり3回目](https://qiita.com/uhyo/items/6f70d94c36d8da5aa5d6)）

## Reactでアニメーションを実装したい

社長「さて、今回はアプリに**いい感じのアニメーション**を追加してもらいたいんや。これからは**UXの時代**やからな」

社長「**React側**に実装を頼むで」

ワイ「承知しましたで」

ハスケル子「やめ太郎さんはReactでアニメーションの実装したことあるんですか？」

ワイ「**無いで**」<font color="#bbbbbb">※この記事における設定です。現実とは異なる可能性がありますのでご注意ください。</small>

ワイ「でもまあCSSで`transition`ってのを使えばええことくらいは知っとるで」

ワイ「アニメーションの実装くらい楽勝やな！」

**〜数時間後〜**

ワイ「あかん、こんがらがってきたで」

ワイ「今回はコンポーネントが増えたり減ったりするんや」

[娘（4歳）](https://qiita.com/Yametaro/items/9b65a21940e001554719)「うん」

ワイ「新しいコンポーネントが増えたときにアニメーションさせなあかん」

娘「うん」

ワイ「でもアニメーションさせるにはまずアニメーション前の状態をレンダリングせなあかん」

娘「うん」

ハスケル子「（何でこの人は娘さんに相談してるんだろう）」

娘「`transition`によるアニメーションはあくまでCSSの変化をアニメーションしてくれるものだから、変化前のCSSの状態を一旦作ることが必要になるんだよね」

ワイ「せや」

娘「コンポーネントが出現するとき、アニメーションの前の状態をまず描画→その後アニメーションさせるという2段階の処理が必要なんだね」

ワイ「せや」

娘「これを実装するには、コンポーネントがマウントされていない状態→コンポーネントがマウントされた状態（CSSは変化前の状態）→コンポーネントがマウントされた状態（CSSは変化後の状態）という2段階の状態変化を実装する必要があるんだね」

ワイ「せや」

ハスケル子「（**この記事娘さんだけでいいんじゃないかな**）」

ワイ「コンポーネントが消えるときも難しいんや」

娘「コンポーネントを消したいときはアニメーションが終わるまでコンポーネントを残しておいて、それから消す必要があるんだね」

ワイ「せや」

娘「意味上はもう消えているコンポーネントを、アニメーションというUIの都合で残しておかないといけないのがReact的じゃなくて辛いよね」

ハスケル子「そういうロジックを組めばいいじゃないですか」

ワイ「まあできないわけやないで」

ワイ「でも何かコードが汚くなってまうんや」

## useTransitionを知る

ハスケル子「ふふふ」

ワイ「何や気味の悪い」

ハスケル子「その辺をいい感じにやってくれるのが**useTransition**ですよ」

ワイ「ほう、ちょっと調べてみよか……おお、**[useTransitionのドキュメント](https://reactjs.org/docs/concurrent-mode-reference.html#usetransition)**があったで」

ハスケル子「そうです、**[useTransitionのドキュメント](https://www.react-spring.io/docs/hooks/use-transition)**に書いてある通りこれで簡単にアニメーションが実装できます」

ワイ「でもこれ次の画面に移るときに使うとか書いてあるで」

> `useTransition` allows components to avoid undesirable loading states by waiting for content to load before **transitioning to the next screen**. It also allows components to defer slower, data fetching updates until subsequent renders so that more crucial updates can be rendered immediately.
> 
> （[useTransitionのドキュメント](https://reactjs.org/docs/concurrent-mode-reference.html#usetransition)から引用）

ハスケル子「ああ、useTransitionはルーターと組み合わせてページ遷移のアニメーションにも使えるんですよ」

> ![4b234568bc38eb568c5fa5be7a6f29da.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233667/220eef92-803d-3ce2-1811-8b2f45a17752.png)
> 
> （[useTransitionのドキュメント](https://www.react-spring.io/docs/hooks/use-transition)から引用）

ハスケル子「というかやめ太郎さん英語のドキュメント読めるんですか」

ワイ「当たり前や」

ワイ「**[人様のキャラやからできるだけ持ち上げとこ思ってな](https://qiita.com/uhyo/items/da4a764f313a3b795d59)**」

ハスケル子「……」

ハスケル子「そのネタ好きですね」

ハスケル子「あと記事冒頭で社長をアホキャラにしてますけど[実在の会社](https://www.yumemi.co.jp/)とは関係ありませんからね」

ワイ「とにかく」

ワイ「この`useTransition`を使ってアニメーションを実装してみるで」

ハスケル子「まあ使い方が[さっきのドキュメント](https://www.react-spring.io/docs/hooks/use-transition)に書いてあるのでそんなに難しくないですよ」

ワイ「探したら**[useTransitionの日本語解説記事](https://qiita.com/uhyo/items/6be96c278c71b0ddb39b)**もあったから余裕やな！（宣伝）」

## useTansitionでアニメーションを実装してみた

**〜翌日〜**

ワイ「**半分だけ実装できたで**」

ハスケル子「**半分**……？」

ワイ「コンポーネントが消えるときはうまく行くんやけど出てくるときがまだ実装できてへんねん」

ハスケル子「`useTransition`をどんな使い方したら**消えるときだけ**なんて挙動になるのか逆に気になりますよ」

ワイ「まあ見てくれや」

- https://codesandbox.io/s/qiita-wai-react-1-y8h2g

ハスケル子「……ボタンがあって押すと青い箱が出たり消えたりするんですね」

![サンプルのスクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233667/095ec906-ce6c-5de9-d4cd-e4a1ea6dec4a.png)

ワイ「消えるときだけアニメーションがかかるやろ」

ハスケル子「どれどれ実装は……**！？**」

ワイ「なんや珍しく驚いた顔なんかしよって」

ワイ「あとワイは[本家](https://qiita.com/Yametaro/items/6a24631687dca63c611a)と違うて絵心は無いから驚いた顔の絵とかは無いで」

```js:index.js
  const [startTransition, isPending] = useTransition({
    timeoutMs: 1000
  });
```

ハスケル子「なんですかこの**[useTransition](https://reactjs.org/docs/concurrent-mode-reference.html#usetransition)**って」

ワイ「なんや、ハスケル子ちゃんが教えてくれたんやろ」

ハスケル子「私が言ってたのは誰もが知ってる**[useTransition](https://www.react-spring.io/docs/hooks/use-transition)**のことですよ」

ハスケル子「**[useTransition](https://reactjs.org/docs/concurrent-mode-reference.html#usetransition)**なんて意味不明な機能知りませんよ、というかまだ**[実験段階](https://ja.reactjs.org/docs/concurrent-mode-intro.html)**じゃないですか」

ワイ「なんや**[useTransition](https://reactjs.org/docs/concurrent-mode-reference.html#usetransition)**やなくて**[useTransition](https://www.react-spring.io/docs/hooks/use-transition)**のこと言っとったんかい！　紛らわしいわ！」

ワイ「ワイもよう分からんようなってきたで、こういうときのための娘ちゃんや」

娘「パパが言ってるのは**React Concurrent Mode**の**[useTransition](https://reactjs.org/docs/concurrent-mode-reference.html#usetransition)**で、ハスケル子ちゃんが言っているのは[react-spring](https://github.com/react-spring/react-spring)の**[useTransition](https://www.react-spring.io/docs/hooks/use-transition)**だよ！」

娘「この記事で扱うのはReact Concurrent ModeのuseTransitionで、react-springは特に関係ないよ！」

ワイ「よう分かったで、さすがワイの娘や！」

ハスケル子「（何なんだろうこの茶番）」

娘「Concurrent Modeの詳しい説明とかuseTransitionの解説は[筆者の既存記事](https://qiita.com/uhyo/items/6be96c278c71b0ddb39b)を見てね！（宣伝）」

ハスケル子「それで、このサンプルはどうやってアニメーションしてるんですか？」

ワイ「せやったな、まず箱が出とるかどうかは`show`というステートで管理するんや」

```jsx:index.js
  const [show, setShow] = useState(false);
```

ワイ「レンダリング部分では`show`が`true`のときだけ`Box`をレンダリングするんや」

```jsx:index.js
  return (
    <div className="App">
      <h1>Animation Sample</h1>
      <p>
        <button onClick={toggle}>toggle</button>
      </p>
      {show ? <Box show={show && !isPending} /> : null}
      <Suspense fallback={null}>
        <Waiter timer={timer} />
      </Suspense>
    </div>
  );
```

ワイ「`Box`は`show={false}`のときは`opacity: 0`で`show={true}`のときは`opacity: 1`や」

ハスケル子「ここにある`isPending`がよく分からないですけど、ここに秘密があるんですね」

ワイ「せや」

ワイ「`toggle`関数では`show`の`true`と`false`を切り替えるんやけど」

ワイ「何も考えんでやると`show`が`false`になった瞬間に箱がDOMから消えるからアニメーションにならんのや」

娘「そこで`useTransition`の出番だね」

ワイ「せや」

ハスケル子「よく見ると`useTransition`を呼んで`startTransition`と`isPending`を取得していますね」

ワイ「せや、そして`startTransition`は`toggle`の中で使われとるで」

```js:index.js
  const toggle = () => {
    if (show) {
      startTransition(() => {
        setShow(false);
        setTimer(new Timer(500));
      });
    } else {
      setShow(true);
    }
  };
```

ワイ「箱が出とるときに`toggle`を呼ぶと`startTransition`が使われるで」

ハスケル子「`startTransition`はコールバック関数を受け取るんですね」

ワイ「せや、これはすぐ呼ばれるで」

ワイ「この中で**ステートの更新**をすると`useTransition`の効果が発揮されるんや」

ハスケル子「今回は`setShow(false)`と`setTimer(new Timer(500))`ですね」

娘「`Timer`ってなに？」

ワイ「ええ質問やな、でもそれは後で説明するで」

ワイ「`useTransition`の効果はな、**ステート更新によって発生したレンダリングが完了するまで画面の更新が遅延される**っちゅうことや」

ハスケル子「？？？」

ワイ「ステートを更新したら当然再レンダリングが起こるやろ」

ハスケル子「はい」

ワイ「実はこのレンダリングが完了するまで500ミリ秒かかるんや」

娘「`Timer`のおかげだね！」

ワイ「せや、ワイが説明する前に理解するとはさすが娘ちゃんやで」

ハスケル子「（あとで娘ちゃんに説明してもらおう）」

ワイ「レンダリング完了まで500ミリ秒かかるってことは`setShow(false)`が画面に反映されるまで500ミリ秒かかるってことやで」

ハスケル子「なるほど、その間にアニメーションさせればいいんですね」

ワイ「物分かりがええやないか」

ハスケル子「でも、肝心のアニメーションはどうやっているんですか？」

ワイ「ここが`isPending`の出番や」

```jsx:index.js
      {show ? <Box show={show && !isPending} /> : null}
```

ワイ「`isPending`は**画面の更新が遅延されている最中に`true`になる**んや。普段は`false`やで」

娘「図を用意したからこれを見ながら説明するよ」

ワイ「さすが娘ちゃんや、天才やな！」

<img width="953" alt="スクリーンショット 2019-12-08 22.52.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233667/5ea805bc-e18f-04c6-710b-dc537d7ca53e.png">

ワイ「最初は`show`が`true`で`isPending`は`false`やから`<Box show={true} />`がレンダリングされとるで」

ワイ「ボタンを押すと`toggle()`が呼ばれるんや」

ハスケル子「図によると、`toggle`を呼んだ瞬間、つまり`startTransition`の中で`setShow(false)`を呼んだ瞬間は`show`は`true`のままで`isPending`も`true`になる」

ハスケル子「そうなると`<Box show={false} />`がレンダリングされるんですね」

ワイ「せや」

ワイ「`Box`はCSSで`transition: opacity 500ms linear`と指定してあるさかい、ここでアニメーションが起こるで」

ハスケル子「そして500ミリ秒後に`show`が`false`になる」

ワイ「せや、これは`startTransition`による遅延が終わったからやな」

ワイ「`isPending`も`false`に戻るんや」

ハスケル子「500ミリ秒というのはちょうどアニメーションにかかる時間ですね」

ワイ「せや、アニメーションが終わった頃に`useTransition`の遅延が終わって`Box`が消されるっちゅう寸法や」

ハスケル子「なるほど……なんとなく分かったような気がします」

ワイ「コードのURLをもう一回貼っとくから自分でいろいろ試してみるんやで」

- https://codesandbox.io/s/qiita-wai-react-1-y8h2g

## レンダリング遅延の仕組み

ハスケル子「ところで、レンダリングが500ミリ秒遅延されたのはどうしてですか？」

ハスケル子「明らかにこの`Timer`が怪しいですよね」

```jsx:index.js
  const [timer, setTimer] = useState(null);
  // ... 中略 ...
        setTimer(new Timer(500));
```

ハスケル子「`timer`はここで描画に使われています」

```jsx:index.js
      <Suspense fallback={null}>
        <Waiter timer={timer} />
      </Suspense>
```

娘「じゃあまず`Timer`について説明するよ！」

娘「実装は別ファイルに書いてあるよ」

```js:Timer.js
export class Timer {
  constructor(duration) {
    const timer = new Promise(resolve => setTimeout(resolve, duration));
    this.done = false;
    this.promise = timer.then(() => {
      this.done = true;
    });
  }
  throwIfNotDone() {
    if (!this.done) {
      throw this.promise;
    }
  }
}
```

娘「`new Timer(duration)`が実行されると、`duration`ミリ秒後に解決される`Promise`が作られるよ」

ハスケル子「それは`this.promise`に入っているんですね」

娘「そして、この`Promise`が解決されたら`this.done`が`true`になるよ」

ハスケル子「この`throwIfNotDone`メソッドは何ですか？」

娘「これは**まだPromiseが解決されていなかったらPromiseをthrowする**というメソッドだよ」

ワイ「`throw`ってエラーが出たときに使う奴ちゃうんか？」

ハスケル子「言語仕様上は`throw`は何でも投げられるんですよね」

娘「この`Promise`を投げるというのがReactのConcurrent Modeの特徴なんだよ」

娘「Reactは、コンポーネントが`Promise`を投げたら**そのコンポーネントの描画が先延ばしにされた**と判断するよ」

ハスケル子「ということは、先延ばしの実態はここにあったんですね」

ワイ「せや、ここで投げられたPromiseを`useTransition`が検知して画面更新の遅延を発生させるんや」

娘「まとめると、`new Timer(500)`は解決に500ミリ秒かかるPromiseを用意したってことなんだよ！」

ハスケル子「じゃあ、これを使う側はどうなっているんですか？」

```jsx:index.js
      <Suspense fallback={null}>
        <Waiter timer={timer} />
      </Suspense>
```

```jsx:index.js
function Waiter({ timer }) {
  if (timer) timer.throwIfNotDone();
  return null;
}
```

ワイ「`Waiter`コンポーネントがPromiseを`throw`する役目を持っとるで」

ワイ「渡された`timer`がまだ解決していなかったらPromiseを投げるんや」

娘「つまり`Waiter`**は渡された`timer`がまだ完了していなかったら完了するまでコンポーネントの描画を先延ばしにする**という役目のコンポーネントだよ」

ハスケル子「`Waiter`の周りにある`Suspense`は何ですか？」

ワイ「Promiseを`throw`するコンポーネントは周りを`Suspense`で囲む必要があるんや」

ワイ「細かいことは[筆者の既存記事](https://qiita.com/uhyo/items/6be96c278c71b0ddb39b)を読むんやで」

娘「まとめるとこうだよ」

娘「`startTransition`の中で`setShow(false)`と同時に`setTimer(new Timer(500))`を実行したよね」

娘「これにより再描画が発生するけど`Waiter`がPromiseを投げることで描画が先延ばしにされる」

ハスケル子「`new Timer(500)`なので500ミリ秒先延ばしになるんですね」

娘「あとはさっきパパが説明した通りだよ」

ワイ「せや」

ワイ「先延ばしになっている間に`useTransition`の効果で`isPending`が`true`になるんや」

ワイ「かわいい娘ちゃんが作った図をもう一度出しておくで」

<img width="953" alt="スクリーンショット 2019-12-08 22.52.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233667/5ea805bc-e18f-04c6-710b-dc537d7ca53e.png">

ワイ「以上がワイの実装の説明やで、随分長くなってもうたな」

ハスケル子「**でもまだ半分しか実装できてないんですよねこれ**」

ワイ「うっ……」

ワイ「待っとけや、もう半分もすぐに実装してくるで」

娘「がんばれパパ！」

## 出てくるときのアニメーションの実装

**〜1ヶ月後〜**

ハスケル子「いやどれだけ時間かかってるんですか」

ワイ「仕方ないやろ、筆者が思いつくまで1ヶ月くらいかかったんや（実話）」

ワイ「まあ上んとこまで記事書いてから考えなおしたら一瞬でできたんやけどな」

娘「考えをまとめ直すのは大事だね！」

ワイ「完全版の実装はこれやで」

- https://codesandbox.io/s/qiita-wai-react-2-uj246

ハスケル子「どれどれ……あまり変わってませんね」

ワイ「変わったのは1箇所だけや、`toggle`の定義部分な」

```js:index.js
  const toggle = () => {
    if (show) {
      startTransition(() => {
        setShow(false);
        setTimer(new Timer(500));
      });
    } else {
      setShow(true);
      startTransition(() => {
        setTimer(new Timer(10));
      });
    }
  };
```

ハスケル子「`false`から`true`になるときは、`setShow(true)`は`startTransition`の外で実行して`setTimer`だけ中で実行するんですね」

ワイ「せや」

娘「こうすると、`toggle`を押した直後は`show`が`true`で`isPending`も`true`の状態になるよ」

ハスケル子「そのときは……`<Box show={false} />`が描画されますね」

娘「そして、10ミリ秒後に`isPending`が`false`になるよ」

ワイ「図にするとこうやで」

<img width="953" alt="スクリーンショット 2019-12-08 23.03.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233667/6c651705-a517-ac1e-c662-58c038fea6ff.png">

ハスケル子「今回も、何も無い状態からまず`opacity: 0`の状態を描画してそれから`opacity: 1`にしているんですね」

ハスケル子「10ミリ秒というのは何の意味があるんですか？」

ワイ「今回は`opacity: 0`の状態を描画するのは一瞬だけでええんや」

ワイ「すぐ`opacity: 1`にしないとアニメーションが開始せんからな」

ワイ「一瞬だけ`opacity: 0`を描画したかったからなるべく短い時間にしたんやけど」

ワイ「`0`とかにすると短すぎてうまくいかへんのや」

娘「0ミリ秒後というのは短すぎてReactが遅延したと認識しないみたいだね」

ハスケル子「なるほど……あれ」

娘「どうしたの？」

ハスケル子「何回もボタンを押しているとたまに箱が出るときのアニメーションが無いですね」

ワイ「せや、10ミリ秒でもたまに短すぎて`useTransition`が働かないときがあるで」

ワイ「**Reactは気まぐれ**やからな」

ハスケル子「100ミリ秒とかもっと長い時間にするのは駄目なんですか？」

ワイ「そしたらアニメーションが始まるのが100ミリ秒間遅れてまうやろ」

娘「逆に言えば、アニメーション開始を遅らせたいときはそれも有効な対策だよ！」

## 今回の実装の欠点

ハスケル子「ところで」

ハスケル子「ボタンを連打したときの動きが変ですよね？」

ワイ「うっ」

ハスケル子「特に、箱が消えている途中でボタン押しても何も起きずにそのまま消えますよね」

ハスケル子「消えている途中でボタンを押したら`show`が`false`から`true`に戻って箱が復活するべきじゃないですか？」

ハスケル子「**宣言的UIが聞いてあきれますね**」

ワイ「そうでもないで」

ワイ「まあワイの実装があかんのは確かやな、今後の課題や」

娘「でも今回`show`を`true`から`false`に変えるのは`startTransition`の中だよね」

娘「ということは**`show`を`false`に変えるのに500ミリ秒かかっている**ってことなんだよ」

ワイ「せや」

ワイ「まだ`show`が`true`のままなんやから、何回ボタン押しても`false`になるだけのほうがええんちゃうか？」

娘「図にするとこうだね」

娘「`toggle`はあくまで`show`が`true`か`false`かで動作を変えているよ」

<img width="953" alt="スクリーンショット 2019-12-08 23.10.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233667/4af0a726-edd7-1dd7-a94b-64c2af40c85a.png">

ハスケル子「そ……それは確かに」

ワイ「せや！　次の**インターンの課題**は今のバグを修正することにするで！」

ハスケル子「うっ……藪蛇でした」

## まとめ

ハスケル子「結局この記事って何がテーマだったんですか？」

ワイ「おう、テーマな」

ワイ「**useTransition**と**アニメーション**をタイトルに入れて**react-spring勢を釣りたい**がテーマや」

ハスケル子「ぐっ……まんまと釣りに加担してしまったわけですか」

社長「おい」

ワイ「しゃ、社長！」

社長「お前この記事が[今年イチ！お勧めしたいテクニック by ゆめみ feat.やめ太郎 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/yumemi_no1)の9日目って知っとんのか？　テーマは**「今年イチ！お勧めしたいテクニック」**だったやろがい！」

ワイ「も、もちろん分かっておりまっせ！　**今年イチお勧めしたいテクニック**は何と言っても`useTransition`ですわ！」

娘「react-springじゃなくてReact Concurrent Modeの`useTransition`だよ！」

ワイ「[筆者の前記事](https://qiita.com/uhyo/items/6be96c278c71b0ddb39b)でも言っとった通り、`useTransition`は状態を複数同時に管理できるんですわ」

ハスケル子「具体的には、『ステート変更反映前で`isPending`が`true`の状態』と『ステート変更反映後の状態』ですね」

ワイ「その2つの状態をうまく扱うことでアニメーションのような時間差処理が必要な処理を綺麗に扱うことができるんでっせ！」

社長「（**綺麗だったか……？**）」

ワイ「一定時間レンダリングを遅延させるために`Timer`と`Waiter`を使うのはなかなか有用なテクニックとちゃいますか！？」

ハスケル子「（**`Waiter`とかかなり無理やりでは……？**）」

ハリー先輩「（**絶対そんな使い方想定されてへんやろ**）」

ワイ「他にも`useTransition`は色々な使い道があるで！　ぜひ使いこなしてや！」

ワイ「**まだ正式リリースされとらんけどな！**」

娘「**今年中にリリースされる可能性はかなり低いよ！**」

ハスケル子「（**今年イチとは何だったのか**）」

### 余談：もうひとつのお勧めテクニック

ワイ「もうひとつ考えたことがあるんや」

ハスケル子「何ですか？」

ワイ「実は真にお勧めしたいテクニック、それは**ワイ記法**や」

ハスケル子「……」

ワイ「筆者はこう見えてもこの記事でワイ記法は3本目や、全部今年やで」

- [今度こそ理解できる！　JavaScriptの参照が完全に分かる記事](https://qiita.com/uhyo/items/da4a764f313a3b795d59)（1回目）
- [ワイ「スリープソート？　寝ている間に小人さんがソートしてくれるんでっか？」](https://qiita.com/uhyo/items/6f70d94c36d8da5aa5d6)（2回目）

ハスケル子「何回も人のネタパクって何やってるんですか一体……」

ハスケル子「それどころかこういう第四の壁越えた茶番は客観的に見ると結構痛いですよ」

ワイ「しゃあないやろ、ワイはワイ記法を使うときは最初から最後まで貫く主義なんや」

ワイ「『くぅ〜疲れましたｗ』よりはマシやろ」

ハスケル子「（人のネタで相撲取っておいて何を言ってるんだか）」

ワイ「まあやってみて考えたことがあるんや、第三者の目線ってやつやな」

ハスケル子「はあ」

ワイ「普段ワイは文章構成とか気を使って書くほうなんやけど」

ワイ「会話形式やと文章構成もクソも無いんや」

娘「思考をそのまま書き下すのが主流みたいだね」

ワイ「でも[本家](https://qiita.com/Yametaro)の記事は分かりやすい言うてめっちゃ評判ええやろ」

ワイ「ワイなりにその理由を考えたんや」

ハスケル子「理由……」

ワイ「まあ一言で言うと**キャラ付け**や」

ワイ「**キャラごとの役割を明確にするのが分かりやすさの理由の一つ**やと思ってこの記事でも実践してみたで」

ハスケル子「私は言うまでもなく聞き手役ですね」

ワイ「せや、解説役はワイと娘ちゃんや」

ハスケル子「2人はどう違うんですか？」

ワイ「まあはっきりした違いがあるわけではないんやけどな」

ワイ「ワイはどちらかというと読者寄り、娘ちゃんは教師役って立ち位置にしてみたで」

ワイ「基本はワイが実装者の目線で説明して娘ちゃんがライブラリの動きとかを解説するんや」

ハスケル子「3人の場合は聞き手、読者役、教師役と分けるといいんですね」

ワイ「まあ一例や」

ワイ「あと解説役が2人いるとやりやすいこともあるで」

娘「特に複数の話題がある場合や解説を後回しにする場合は、話題の担当者を明確にすることで読者の記憶を助ける効果もあると思うよ！」

ワイ「ほら、娘ちゃんは教師役さかい賢そうなしゃべり方なんや」

ハスケル子「賢そうというかなんか地の文に近くて堅いですね」

ワイ「まあ感覚で書いとる部分もあるんやけど、こういう所もキャラ付けに気を遣ったんやで」

ワイ「あとワイはレンダリングのことを『レンダリング』と呼ぶけど娘ちゃんは『描画』って呼んどるで」

ハスケル子「はあ」

ワイ「まあ**ワイ記法**も奥が深いってことを言いたかったんや」

ワイ「結構楽しいからみんなも**ワイ記法**で記事書いてみてや！」

〜完〜