blog.bouzuya.net

2018-12-13 purescript-react-basic で dangerouslySetInnerHTML / 『王とサーカス』を読んだ

purescript-react-basic で dangerouslySetInnerHTML っぽいことをしようとした話。

Markdown を HTML (String) にして表示したい。

しかし purescript-react-basic には React の dangerouslySetInnerHTML に相当するものがない。 https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml

そこで代わりに Element を得て innerHTML に設定したい。

しかし purescript-react-basic には Element を得るための関数がない。そこで React.Basic.DOM.Components.Refref を使って Node を得る。それから Web.DOM.ElementfromNode を使って NodeElement にする。

Element は得られた。

しかし purescript-web-dom の ElementinnerHTML がない。 https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML

そこで innerHTML に設定する関数 unsafeSetInnerHTML を定義する。

foreign import unsafeSetInnerHTML :: String -> Element -> Effect Unit
"use strict";

exports.unsafeSetInnerHTML = function (s) {
  return function (e) {
    return function () {
      e.innerHTML = s;
    };
  };
};

この unsafeSetInnerHTML を呼び出したい。

しかし ref :: (Maybe Node -> JSX) -> JSX では Effect が動かせない。

そこで React.Basic.Components.Asyncasync で実行する。

async :: Aff JSX -> JSX

ソースコードのコメント (※ドキュメントには書かれていない) によると async は再描画が動かないようなので React.Basickeyed で wrap してやる。

-- , didUpdate: No! Implementing `didUpdate` breaks the
--               Aff/Component lifecycle relationship.
--               To update the Aff over time, wrap this
--               component with `keyed`.

keyed :: String -> JSX -> JSX

……で出来上がったものがこれ。

, Ref.ref
    (\nodeMaybe ->
      fromMaybe JSX.empty do
        node <- nodeMaybe
        element <- Element.fromNode node
        pure
          (keyed
            self.state.article
            (Async.async do
              liftEffect
                (unsafeSetInnerHTML
                  (Markdown.toHtmlString self.state.article)
                  element)
              pure JSX.empty)))

https://github.com/bouzuya/purescript-react-basic-bbn-viewer/blob/c857bf88fb2514c81ecb8c2752de70f72ddc6618/src/Component/App.purs#L108-L121

Markdown を HTML にしてから innerHTML へ設定したかっただけなんだ……。それがこの「しかし……」「そこで……」の繰り返しときたもんだ。

追記: 2018-12-18element を使った方法に書き直した。そちらのほうがより簡潔だ。


米澤穂信さんの『王とサーカス』を読み終えた。

『さよなら妖精』 (2018-12-04) の大刀洗さんが主人公だ。物語としての繋がりはない。フリーの記者になっている。舞台はネパール。

「だが私は、この国をサーカスにするつもりはないのだ。もう二度と」

主人公が登場人物のひとりから言われたもの。サーカスという「演し物(だしもの)」として消費してくれるなという意味だ。

報道に対する姿勢。誰かに何かを伝えること・伝えないことの選択。インターネット・ウェブ・パソコン・スマートフォンなどの登場で個人の発信力が強化されている。個人の単位でもこういう報道に対する姿勢のようなものを考えることの重要性は増しているんだろうな……。

こんなことを書くのは『コモンズ』 (2018-12-06) を読んだせいもあるのだと思う。まさに↑の個人の強化を背景とした変化について書かれていた。個人が創造・発信する機会を得た時代におけるコモンズの重要性。それを殺すようなコントロールへの警鐘だ。

伝えることができるからには考えないといけないのだろうな。