import { jsx, jsxs, Fragment } from 'solid-jsx/jsx-runtime';

/*@jsxRuntime automatic @jsxImportSource solid-jsx*/
const toc = [{
  "depth": 1,
  "value": "リアクティビティ",
  "children": [{
    "depth": 2,
    "value": "プリミティブの紹介",
    "children": []
  }, {
    "depth": 2,
    "value": "動作の仕組み",
    "children": []
  }, {
    "depth": 2,
    "value": "考慮すべき点",
    "children": []
  }]
}];
function _createMdxContent(props) {
  const _components = Object.assign({
    h1: "h1",
    a: "a",
    p: "p",
    code: "code",
    pre: "pre",
    span: "span",
    h2: "h2",
    ol: "ol",
    li: "li"
  }, props.components);
  return jsxs(Fragment, {
    children: [jsxs(_components.h1, {
      id: "リアクティビティ",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#リアクティビティ",
        children: "#"
      }), "リアクティビティ"]
    }), "\n", jsx(_components.p, {
      children: "Solid のデータ管理は、すべての更新を担当する一連の柔軟なリアクティブプリミティブで構築されています。MobX や Vue と非常に似たアプローチをとっていますが、仮想 DOM のために粒度を変えることはありません。Effect や JSX ビューのコードでリアクティブな値にアクセスすると、依存関係が自動的に追跡されます。"
    }), "\n", jsxs(_components.p, {
      children: ["Solid のプリミティブは、主にタプルを返す ", jsx(_components.code, {
        children: "create"
      }), " を呼び出す形で提供されています。大抵の場合、タプルの最初の要素は読み取り可能なプリミティブで、2 番目の要素はセッターです。読み取り可能な部分のみをプリミティブ名で参照するのが一般的です。"]
    }), "\n", jsxs(_components.p, {
      children: ["これは ", jsx(_components.code, {
        children: "count"
      }), " Signal の変更に基づいて更新される、基本的な自動インクリメントカウンターです。"]
    }), "\n", jsx(_components.pre, {
      children: jsxs(_components.code, {
        className: "hljs language-jsx",
        children: [jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { createSignal, onCleanup } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"solid-js\""
        }), ";\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { render } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"solid-js/web\""
        }), ";\n\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "App"
        }), " = (", jsx(_components.span, {
          className: "hljs-params"
        }), ") => {\n  ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " [count, setCount] = ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createSignal"
        }), "(", jsx(_components.span, {
          className: "hljs-number",
          children: "0"
        }), "),\n    timer = ", jsx(_components.span, {
          className: "hljs-built_in",
          children: "setInterval"
        }), "(", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "setCount"
        }), "(", jsx(_components.span, {
          className: "hljs-title function_",
          children: "count"
        }), "() + ", jsx(_components.span, {
          className: "hljs-number",
          children: "1"
        }), "), ", jsx(_components.span, {
          className: "hljs-number",
          children: "1000"
        }), ");\n  ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "onCleanup"
        }), "(", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " ", jsx(_components.span, {
          className: "hljs-built_in",
          children: "clearInterval"
        }), "(timer));\n\n  ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "return"
        }), " ", jsxs(_components.span, {
          className: "xml",
          children: [jsxs(_components.span, {
            className: "hljs-tag",
            children: ["<", jsx(_components.span, {
              className: "hljs-name",
              children: "div"
            }), ">"]
          }), "{count()}", jsxs(_components.span, {
            className: "hljs-tag",
            children: ["</", jsx(_components.span, {
              className: "hljs-name",
              children: "div"
            }), ">"]
          })]
        }), ";\n};\n\n", jsx(_components.span, {
          className: "hljs-title function_",
          children: "render"
        }), "(", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " ", jsx(_components.span, {
          className: "xml",
          children: jsxs(_components.span, {
            className: "hljs-tag",
            children: ["<", jsx(_components.span, {
              className: "hljs-name",
              children: "App"
            }), " />"]
          })
        }), ", ", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "document"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "getElementById"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"app\""
        }), "));\n"]
      })
    }), "\n", jsxs(_components.h2, {
      id: "プリミティブの紹介",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#プリミティブの紹介",
        children: "#"
      }), "プリミティブの紹介"]
    }), "\n", jsx(_components.p, {
      children: "Solid は、Signal、Memo、Effect の 3 つの主要なプリミティブで構成されています。これらのプリミティブの核となるのは、Memo と Effect をラップすることで Signal（と Memo）を追跡するオブザーバーパターンです。"
    }), "\n", jsx(_components.p, {
      children: "Signal は最もコアとなるプリミティブです。Signal には値が含まれており、読み書きされたときにインターセプトできるように get と set の関数が用意されています。"
    }), "\n", jsx(_components.pre, {
      children: jsxs(_components.code, {
        className: "hljs language-js",
        children: [jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " [count, setCount] = ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createSignal"
        }), "(", jsx(_components.span, {
          className: "hljs-number",
          children: "0"
        }), ");\n"]
      })
    }), "\n", jsx(_components.p, {
      children: "Effect は、Signal の読み込みをラップし、依存する Signal の値が変更されるたびに再実行する関数です。これは、レンダリングなどの副作用を作成するのに便利です。"
    }), "\n", jsx(_components.pre, {
      children: jsxs(_components.code, {
        className: "hljs language-js",
        children: [jsx(_components.span, {
          className: "hljs-title function_",
          children: "createEffect"
        }), "(", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " ", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "console"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "log"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"The latest count is\""
        }), ", ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "count"
        }), "()));\n"]
      })
    }), "\n", jsx(_components.p, {
      children: "最後に、Memo はキャッシュされた派生値です。Memo は Signal と Effect の両方の特性を持っています。依存する Signal を追跡し、それらが変更されたときにのみ再実行され、Memo 自体も追跡可能な Signal です。"
    }), "\n", jsx(_components.pre, {
      children: jsxs(_components.code, {
        className: "hljs language-js",
        children: [jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " fullName = ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createMemo"
        }), "(", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " ", jsxs(_components.span, {
          className: "hljs-string",
          children: ["`", jsx(_components.span, {
            className: "hljs-subst",
            children: "${firstName()}"
          }), " ", jsx(_components.span, {
            className: "hljs-subst",
            children: "${lastName()}"
          }), "`"]
        }), ");\n"]
      })
    }), "\n", jsxs(_components.h2, {
      id: "動作の仕組み",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#動作の仕組み",
        children: "#"
      }), "動作の仕組み"]
    }), "\n", jsx(_components.p, {
      children: "Signal は、サブスクリプションのリストを保持するイベントエミッタです。Signal は、値が変わるたびにサブスクライバーに通知します。"
    }), "\n", jsx(_components.p, {
      children: "さらに興味深いのは、これらのサブスクリプションがどのように行われるかということです。Solid は自動的な依存関係追跡を使用しています。データが変更されると自動的に更新されます。"
    }), "\n", jsx(_components.p, {
      children: "この秘訣は、ランタイムのグローバルスタックにあります。Effect や Memo が開発者から提供された関数を実行（または再実行）する前に、そのスタックに自分自身をプッシュします。そして、読み込まれた Signal は、スタック上に現在のリスナーがあるかどうかをチェックし、あればそのリスナーをサブスクリプションに追加します。"
    }), "\n", jsx(_components.p, {
      children: "このように考えることができます:"
    }), "\n", jsx(_components.pre, {
      children: jsxs(_components.code, {
        className: "hljs language-js",
        children: [jsx(_components.span, {
          className: "hljs-keyword",
          children: "function"
        }), " ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createSignal"
        }), "(", jsx(_components.span, {
          className: "hljs-params",
          children: "value"
        }), ") {\n  ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " subscribers = ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "new"
        }), " ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Set"
        }), "();\n\n  ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "read"
        }), " = (", jsx(_components.span, {
          className: "hljs-params"
        }), ") => {\n    ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " listener = ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "getCurrentListener"
        }), "();\n    ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "if"
        }), " (listener) subscribers.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "add"
        }), "(listener);\n    ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "return"
        }), " value;\n  };\n\n  ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "write"
        }), " = (", jsx(_components.span, {
          className: "hljs-params",
          children: "nextValue"
        }), ") => {\n    value = nextValue;\n    ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "for"
        }), " (", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " sub ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "of"
        }), " subscribers) sub.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "run"
        }), "();\n  };\n\n  ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "return"
        }), " [read, write];\n}\n"]
      })
    }), "\n", jsx(_components.p, {
      children: "これで、Signal を更新するたびに、どの Effect を再実行すればよいかがわかります。シンプルで効果的です。実際の実装はもっと複雑ですが、これが、起こっていることの根幹です。"
    }), "\n", jsx(_components.p, {
      children: "リアクティビティの仕組みをより詳しく理解するには、以下の記事が役立ちます:"
    }), "\n", jsx(_components.p, {
      children: jsx(_components.a, {
        href: "https://dev.to/ryansolid/a-hands-on-introduction-to-fine-grained-reactivity-3ndf",
        children: "A Hands-on Introduction to Fine-Grained Reactivity"
      })
    }), "\n", jsx(_components.p, {
      children: jsx(_components.a, {
        href: "https://dev.to/ryansolid/building-a-reactive-library-from-scratch-1i0p",
        children: "Building a Reactive Library from Scratch"
      })
    }), "\n", jsx(_components.p, {
      children: jsx(_components.a, {
        href: "https://indepth.dev/posts/1289/solidjs-reactivity-to-rendering",
        children: "SolidJS: Reactivity to Rendering"
      })
    }), "\n", jsxs(_components.h2, {
      id: "考慮すべき点",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#考慮すべき点",
        children: "#"
      }), "考慮すべき点"]
    }), "\n", jsx(_components.p, {
      children: "リアクティビティに対するこのアプローチは、非常にパワフルでダイナミックです。条件付きコードの異なるブランチを実行することで、依存関係がその場で変化することに対応できます。また、何段階もの間接参照でも機能します。追跡スコープ内で実行された関数もすべて追跡されます。"
    }), "\n", jsx(_components.p, {
      children: "ただし、注意しなければならない重要な動作とトレードオフがいくつかあります。"
    }), "\n", jsxs(_components.ol, {
      children: ["\n", jsxs(_components.li, {
        children: ["\n", jsx(_components.p, {
          children: "すべてのリアクティビティは、直接またはゲッター/プロキシの下に隠されているかどうかにかかわらず関数の呼び出しから追跡され、プロパティアクセスによってトリガーされます。つまり、どこでリアクティブオブジェクトのプロパティにアクセスするかが重要になります。"
        }), "\n"]
      }), "\n", jsxs(_components.li, {
        children: ["\n", jsx(_components.p, {
          children: "制御フローからのコンポーネントやコールバックは、スコープを追跡せず、一度しか実行されません。つまり、コンポーネント内のトップレベルでロジックを実行したり分割代入しても、再実行されないということです。コードのその部分を再評価するためには、他のリアクティブプリミティブや JSX からこれらの Signal、Store、props にアクセスする必要があります。"
        }), "\n"]
      }), "\n", jsxs(_components.li, {
        children: ["\n", jsx(_components.p, {
          children: "この方法では、同期的にしか追跡できません。Effect で setTimeout があったり、async 関数を使用したりしても、事後に非同期を実行するコードは追跡されません。"
        }), "\n"]
      }), "\n"]
    })]
  });
}
function MDXContent(props = {}) {
  const {wrapper: MDXLayout} = props.components || ({});
  return MDXLayout ? jsx(MDXLayout, Object.assign({}, props, {
    children: jsx(_createMdxContent, props)
  })) : _createMdxContent(props);
}

export { MDXContent as default, toc };
//# sourceMappingURL=reactivity-cf69b0bc.js.map
