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": "Особенности реактивности Solid",
    "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", jsxs(_components.p, {
      children: ["Управление данными в Solid построено на гибких реактивных примитивах, которые отвечают за все обновления. Solid использует подход, очень похожий на MobX или Vue, за тем исключением, что он не жертвует своей точностью в пользу Virtual DOM. Зависимости автоматически отслеживаются, когда вы обращаетесь к реактивным значениям в ", jsx(_components.code, {
        children: "Эффектах"
      }), " и JSX."]
    }), "\n", jsxs(_components.p, {
      children: ["Примитивы Solid представлены в виде ", jsx(_components.code, {
        children: "create"
      }), " функций, в основном возвращающих кортежи (", jsx(_components.code, {
        children: "tuples"
      }), "), в которых первый элемент обычно является считываемым примитивом - ", jsx(_components.a, {
        href: "https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Functions/get",
        children: "геттером"
      }), ", а второй - обновляющим ", jsx(_components.a, {
        href: "https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Functions/set",
        children: "сеттером"
      }), ". Обычно, когда мы говорим о названии примитива (например ", jsx(_components.code, {
        children: "Сигнале"
      }), "), мы имеем в виду считываемую часть."]
    }), "\n", jsxs(_components.p, {
      children: ["Вот, к примеру, базовый счетчик, который увеличивается раз в секунду, и обновляет наш UI в зависимости от значения ", jsx(_components.code, {
        children: "Сигнала"
      }), " ", jsx(_components.code, {
        children: "count"
      }), ":"]
    }), "\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", jsxs(_components.p, {
      children: ["Solid состоит из 3 основных примитивов: ", jsx(_components.code, {
        children: "Сигнал"
      }), ", ", jsx(_components.code, {
        children: "Мемо"
      }), " и ", jsx(_components.code, {
        children: "Эффект"
      }), ". В их основе лежит паттерн наблюдатель (", jsx(_components.code, {
        children: "observer"
      }), "), в котором ", jsx(_components.code, {
        children: "Сигналы"
      }), " (и ", jsx(_components.code, {
        children: "Мемо"
      }), ") отслеживаются путем использования в ", jsx(_components.code, {
        children: "Мемо"
      }), " и ", jsx(_components.code, {
        children: "Эффекты"
      }), "."]
    }), "\n", jsxs(_components.p, {
      children: [jsx(_components.code, {
        children: "Сигналы"
      }), " — простейшие примитивы. Они содержат значение, а также геттеры и сеттеры, чтобы мы знали, когда они считываются и обновляются."]
    }), "\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", jsxs(_components.p, {
      children: [jsx(_components.code, {
        children: "Эффекты"
      }), " — это функции, которые оборачивают считывание нашего ", jsx(_components.code, {
        children: "Сигнала"
      }), " и повторно вызываются при изменении значения зависимого ", jsx(_components.code, {
        children: "Сигнала"
      }), ". Это полезно для создания сайд эффектов, таких как, например, рендеринг."]
    }), "\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: "\"Последнее значение счетчика\""
        }), ", ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "count"
        }), "()));\n"]
      })
    }), "\n", jsxs(_components.p, {
      children: [jsx(_components.code, {
        children: "Мемо"
      }), " — это кэшированные производные значения. Они обладают свойствами как ", jsx(_components.code, {
        children: "Сигналов"
      }), ", так и Эффектов. Они отслеживают свои собственные зависимые ", jsx(_components.code, {
        children: "Сигналы"
      }), ", повторно выполняясь только при их изменении, а также сами являются отслеживаемыми ", jsx(_components.code, {
        children: "Сигналами"
      }), "."]
    }), "\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", jsxs(_components.p, {
      children: [jsx(_components.code, {
        children: "Сигналы"
      }), " — это эмиттеры событий, которые содержат список подписок. Они уведомляют своих подписчиков всякий раз, когда их значение меняется."]
    }), "\n", jsx(_components.p, {
      children: "Еще более интересно то, как происходит подписка на события. Solid использует автоматическое отслеживание зависимостей. Обновления происходят автоматически, как только данные изменяются."
    }), "\n", jsxs(_components.p, {
      children: ["Вся суть заключается в глобальном стеке во время выполнения. Прежде, чем ", jsx(_components.code, {
        children: "Эффект"
      }), " или ", jsx(_components.code, {
        children: "Мемо"
      }), " выполнят (или выполнят повторно) функцию, переданную разработчиком, они помещают себя в этот самый стек. Затем любой ", jsx(_components.code, {
        children: "Сигнал"
      }), " при считывании значения проверяет, есть ли подписчик в стеке, и если есть, то добавляет его в список подписок."]
    }), "\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", jsxs(_components.p, {
      children: ["Теперь всякий раз, когда мы обновляем ", jsx(_components.code, {
        children: "Сигнал"
      }), ", мы знаем, какие ", jsx(_components.code, {
        children: "Эффекты"
      }), " нужно запустить повторно. Просто, но эффективно. Фактическая реализация, конечно, намного сложнее, но суть происходящего именно такова."]
    }), "\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: "Практическое введение в реактивность"
      })
    }), "\n", jsx(_components.p, {
      children: jsx(_components.a, {
        href: "https://dev.to/ryansolid/building-a-reactive-library-from-scratch-1i0p",
        children: "Создание реактивной библиотеки с нуля"
      })
    }), "\n", jsx(_components.p, {
      children: jsx(_components.a, {
        href: "https://indepth.dev/posts/1289/solidjs-reactivity-to-rendering",
        children: "SolidJS: От реактивности до рендеринга"
      })
    }), "\n", jsxs(_components.h2, {
      id: "особенности-реактивности-solid",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#особенности-реактивности-solid",
        children: "#"
      }), "Особенности реактивности Solid"]
    }), "\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", jsxs(_components.p, {
          children: ["Компоненты и обратные вызовы из потоков управления не отслеживают области видимости и выполняются только один раз. Это означает, что деструктуризация или выполнение логики верхнего уровня в ваших компонентах не будет выполняться повторно. Доступ к этим ", jsx(_components.code, {
            children: "Сигналам"
          }), ", ", jsx(_components.code, {
            children: "Сторам"
          }), " и ", jsx(_components.code, {
            children: "Пропсам"
          }), " должен быть осуществлен внутри других реактивных примитивов или JSX, чтобы эта часть кода могла быть повторно оценена."]
        }), "\n"]
      }), "\n", jsxs(_components.li, {
        children: ["\n", jsxs(_components.p, {
          children: ["В данном подходе отслеживание идет только синхронно. Если у вас есть setTimeout или же вы используете асинхронную функцию в своем ", jsx(_components.code, {
            children: "createEffect"
          }), ", код, который будет выполняться асинхронно, не будет отслеживаться."]
        }), "\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-fa84bad4.js.map
