{"componentChunkName":"component---src-templates-docs-js","path":"/docs/thinking-in-react.html","result":{"data":{"markdownRemark":{"html":"<p>Нам кажется, React — это отличный способ писать большие и быстрые JavaScript-приложения. Мы в Facebook и Instagram убедились в его хорошей масштабируемости.</p>\n<p>Одна из особенностей React — это предлагаемый им процесс мышления при создании приложений. В этом руководстве мы разберём пример создания таблицы продуктов с поиском на React.</p>\n<h2 id=\"start-with-a-mock\"><a href=\"#start-with-a-mock\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Начнём с макета </h2>\n<p>Представьте, что у вас уже есть JSON API и макет дизайна сайта. Вот как он выглядит: </p>\n<p>\n  <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 228px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 121.42857142857144%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAYCAIAAAB1KUohAAAACXBIWXMAABYlAAAWJQFJUiTwAAACZUlEQVQ4y4VU23KqQBD0/z8nL0bjJeId8aggctOggmDQIypKFIVNy6ZSpiKkH6aWWXpnenZmM4SQKIqud7g8AvzkFzJguq673+89z4M9HA4fP+H7Pix2f/Nv5OVyaRgG7Gq12m635BFOpxPiPyDjbHAcx/FibDYb2OPxCLvb7fYx8APiB0GAU7CgWdzI2EPker3e6XQURanVao1GAwt42u02bKvVYllWVVWe5yuVCn5AmjcyLRhNA+dhHYYh9VALZxgjivG9+CLLsowjNU2zbZt6kSSyGI/Hi8WCJONGFkUxm81yHIdUqRdCms3mYDDA1h9kRNB1HWGhSo8hCAKCT6dTOO91PSAj51wu1+v1EKdYLHa7XeSMT9RpOBz+QZ7NZvP5HDl/i8QNgTaZTHAc1fKQn6HlAR85j0Yjmic04yA4kblpmmlk1FkUhImmqYoiiSKaAJFRP/ghHneTVjDTtkfTqWIYqmFopnmNew5MSICcJMFfZNLpkNdX0mwShokYBva/rrc5TpYk3Ba0pKVNLIugqiiMphH8qmmnw+FN1y3LgmBMSxq5VK0+vbxUOS7PMBWWLaM/Wq0UqT/IK8cxZjPn/d00DKzXjmNbFgbwvs+T21OS+jyvyvIYZRdFSZZHolgoFDBStEnT0j5igm17vdt9XC62aTrLJd4WCMaEr9drrFOrXauR52dSKKDmEcsSz1u5bpVhELzf76Nhkzr8Rg48L/R94rrRdntGnOv1fD7TmHhM0H94QBIjC5iHUukfz/eHw3nc23go0GHlchkTks/nISExMkrqx8DjRL3wBDHOMZKu7ROsMUWkc+uRSQAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n    >\n      <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px white;\"\n        alt=\"Mockup\"\n        title=\"\"\n        src=\"/static/1071fbcc9eed01fddc115b41e193ec11/d4770/thinking-in-react-mock.png\"\n        srcset=\"/static/1071fbcc9eed01fddc115b41e193ec11/65ed1/thinking-in-react-mock.png 210w,\n/static/1071fbcc9eed01fddc115b41e193ec11/d4770/thinking-in-react-mock.png 228w\"\n        sizes=\"(max-width: 228px) 100vw, 228px\"\n      />\n    </span>\n  </span>\n  </p>\n<p>Наш JSON API возвращает данные, которые выглядят так:</p>\n<div class=\"gatsby-highlight\" data-language=\"jsxon\"><pre class=\"gatsby-code-jsxon\"><code class=\"gatsby-code-jsxon\">[\n  {category: &quot;Sporting Goods&quot;, price: &quot;$49.99&quot;, stocked: true, name: &quot;Football&quot;},\n  {category: &quot;Sporting Goods&quot;, price: &quot;$9.99&quot;, stocked: true, name: &quot;Baseball&quot;},\n  {category: &quot;Sporting Goods&quot;, price: &quot;$29.99&quot;, stocked: false, name: &quot;Basketball&quot;},\n  {category: &quot;Electronics&quot;, price: &quot;$99.99&quot;, stocked: true, name: &quot;iPod Touch&quot;},\n  {category: &quot;Electronics&quot;, price: &quot;$399.99&quot;, stocked: false, name: &quot;iPhone 5&quot;},\n  {category: &quot;Electronics&quot;, price: &quot;$199.99&quot;, stocked: true, name: &quot;Nexus 7&quot;}\n];</code></pre></div>\n<h2 id=\"step-1-break-the-ui-into-a-component-hierarchy\"><a href=\"#step-1-break-the-ui-into-a-component-hierarchy\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Шаг 1: Разобьём интерфейс на составляющие </h2>\n<p>Первое, что нужно сделать — выделить отдельные компоненты (и подкомпоненты) в макете и дать им имена. Если вы работаете с дизайнерами, вполне возможно, что они уже как-то называют компоненты — вам стоит пообщаться! Например, слои Photoshop часто подсказывают имена для React-компонентов.</p>\n<p>Но как узнать, что стоит делать отдельным компонентом, а что нет? Используйте тот же подход, как при решении создать простую функцию или целый объект. Можно применить <a href=\"https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D0%BD%D1%86%D0%B8%D0%BF_%D0%B5%D0%B4%D0%B8%D0%BD%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D0%B8\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">принцип единственной ответственности</a>: каждый компонент должен заниматься какой-то одной задачей. Если функциональность компонента увеличивается с течением времени, его следует разбить на более мелкие подкомпоненты.</p>\n<p>Многие интерфейсы работают с моделью данных JSON. Поэтому хорошо построенная модель, как правило, уже отражает пользовательский интерфейс (а значит, и структуру компонентов). Интерфейс и модели данных часто имеют похожую <em>информационную архитектуру</em>, так что разделить интерфейс на части не составляет труда. Разбейте его на компоненты, каждый из которых отображает часть модели данных.</p>\n<p>\n  <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 275px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 116.1904761904762%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAXCAIAAACEf/j0AAAACXBIWXMAABYlAAAWJQFJUiTwAAADjklEQVQ4y32UaXOjOBCG5///mZ1PM9lsbMcXvsExxge+MPbY5pIQCCTOHuFM1klt1cKDqqXiVR+0+AbiKjOArBr/H/hEtVJ+ExanxHY5wsxDAl6B/wPirscEnscsh0dBCGVSiUnAAlomacqTjPH0K4kgZkmS5kUJeVEFyhJAfgLAKzENE+Szk2k4tm1ZtzAMREhlUYgH7pYg4bzKr6zEPAWffIiDkAVRTikRSoyRT3xBFFGxizACMfo4pCHj7D5GX8WEB0FBkD9T1KW2Xi30N0VdLzf6aiuPp8KeyjPzcNrqe3mkLLUlpYXvp+/iHNNAtbDuoSONtz7Z+sE+CNcu2mBi0Ggf0ENA9yQUi8IwQrpwA4dQAFGwIsMgwr39ePnRkBraei6yyiEfKP1a+0VdzzLIWMk48ARE3iLkhAL1CwfyTIhzr7idGB9t9ur5Mt4d9pjojreynOnxpNseAUBliQHeEdMzpG7uQpFWnhHYS4S+//wpyZO61H1qNBqSJIznVlNeaGGWeVGE4ljgxTGJ2C6hTuFCnv7x7J+OW13X5uqbolzOZyiL2VRZzOfyZHzY79KEi9rHEY2jkMUscH/h5Ca8Vp7d0mJb/VenZXZam3+ePWUCp+NRTLtto9WM9RVcznA2Pzjxo45S648YgYU360G9pvZ743ZTHQ4gIItOW2s114MeEB8cG1znjg2exy+Hh9gBu1gt4O8naDag9gLPTzAZHXqS0Zd2nbanzYW4vF7gdr1j8fPuIXbBIsbBrddCqRv0pLDVpOvV21xV3qbyVDHMYxhRLNouEO3mkzB0vcvnsO05xs/dbn04bIxGjfH4ddC3bLtqZtEKWUY5i0TNEk4TLu5DHtuPape3m3XtjwZjeSLP3maaJquzvjyZLjRFm+/OJxRRJyBuGAi8kF59C2X2u2chtuLDbtXr7qeypa+XUvesyGq9tm63Vq1XZ70EJF65gW2BfQPHuef88amc0ioOO/j+F7w2oPkK4xFgbzMaKvWaPuhrnVZqXQEjsQUgFzBm1+OXgiWbVSR1smEv7UvRsAemcei09NeaIbWNbis/7uF8/MDk5uM7VzlT8yj3B7OJvFksieuJU7CdqauJshxPFuOJOPHVuRCnI2bAM+5eUdVheSW28wtiN983PWwgZPjkhH0T+SYmJ/RufIJgU7jycvtebfG/SQkvHjAxlkFl5J/Wxcq/FKTIiPiB/gZ6RfG+cqwoSwAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n    >\n      <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px white;\"\n        alt=\"Component diagram\"\n        title=\"\"\n        src=\"/static/eb8bda25806a89ebdc838813bdfa3601/6b2ea/thinking-in-react-components.png\"\n        srcset=\"/static/eb8bda25806a89ebdc838813bdfa3601/65ed1/thinking-in-react-components.png 210w,\n/static/eb8bda25806a89ebdc838813bdfa3601/6b2ea/thinking-in-react-components.png 275w\"\n        sizes=\"(max-width: 275px) 100vw, 275px\"\n      />\n    </span>\n  </span>\n  </p>\n<p>Здесь мы видим, что наше приложение состоит из пяти различных компонентов. Курсивом выделены данные, которые эти компоненты представляют.</p>\n<ol>\n<li><strong><code class=\"gatsby-code-text\">FilterableProductTable</code> (оранжевый):</strong> контейнер, содержащий пример целиком</li>\n<li><strong><code class=\"gatsby-code-text\">SearchBar</code> (синий):</strong> поле <em>пользовательского ввода</em></li>\n<li><strong><code class=\"gatsby-code-text\">ProductTable</code> (зелёный):</strong> отображает и фильтрует <em>список данных</em>, основанный на <em>пользовательском вводе</em></li>\n<li><strong><code class=\"gatsby-code-text\">ProductCategoryRow</code> (голубой):</strong> наименования <em>категорий</em></li>\n<li><strong><code class=\"gatsby-code-text\">ProductRow</code> (красный):</strong> отдельно взятый <em>товар</em></li>\n</ol>\n<p>Обратите внимание, что внутри <code class=\"gatsby-code-text\">ProductTable</code> заголовок таблицы («Name» и «Price») сам по себе отдельным компонентом не является. Отделять его или нет — вопрос личного предпочтения. В данном примере мы решили не придавать этому особого значения и оставить заголовок частью большего компонента <code class=\"gatsby-code-text\">ProductTable</code>, так как он является всего лишь малой частью общего <em>списка данных</em>. Тем не менее, если в будущем заголовок пополнится новыми функциями (например, возможностью сортировать товар), имеет смысл извлечь его в самостоятельный компонент <code class=\"gatsby-code-text\">ProductTableHeader</code>.</p>\n<p>Теперь, когда мы определили компоненты в нашем макете, давайте расположим их согласно иерархии. Компоненты, которые являются частью других компонентов, в иерархии отображаются как дочерние:</p>\n<ul>\n<li>\n<p><code class=\"gatsby-code-text\">FilterableProductTable</code></p>\n<ul>\n<li><code class=\"gatsby-code-text\">SearchBar</code></li>\n<li>\n<p><code class=\"gatsby-code-text\">ProductTable</code></p>\n<ul>\n<li><code class=\"gatsby-code-text\">ProductCategoryRow</code></li>\n<li><code class=\"gatsby-code-text\">ProductRow</code></li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"step-2-build-a-static-version-in-react\"><a href=\"#step-2-build-a-static-version-in-react\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Шаг 2: Создадим статическое приложение в React </h2>\n<p data-height=\"600\" data-theme-id=\"0\" data-slug-hash=\"BwWzwm\" data-default-tab=\"js\" data-user=\"lacker\" data-embed-version=\"2\" class=\"codepen\">Пример кода <a href=\"https://codepen.io/gaearon/pen/BwWzwm\">Философия React: Шаг 2</a> на <a href=\"https://codepen.io\">CodePen</a>.</p>\n<script async src=\"https://production-assets.codepen.io/assets/embed/ei.js\"></script>\n<p>Теперь, когда все компоненты расположены в иерархическом порядке, пришло время воплотить в жизнь наше приложение. Самый лёгкий способ — создать версию, которая использует модель данных и рендерит интерфейс, но не предполагает никакой интерактивности. Разделять эти процессы полезно. Написание статического приложения требует много печатания и совсем немного мышления. С другой стороны, создание интерактивного приложения подразумевает более глубокий мыслительный процесс и лишь долю рутинной печати. Позже мы разберёмся, почему так получается.</p>\n<p>Чтобы построить статическое приложение, отображающее модель данных, нам нужно создать компоненты, которые используют другие компоненты и передают данные через <em>пропсы</em>. <em>Пропсы</em> — это способ передачи данных от родителя к потомку. Если вы знакомы с понятием <em>состояния</em>, то для статического приложения это как раз то, чего вам <strong>использовать не нужно</strong>. Состояние подразумевает собой данные, которые меняются со временем — интерактивность. Так как мы работаем над статическим приложением, нам этого не нужно.</p>\n<p>Написание кода можно начать как сверху вниз (с большого <code class=\"gatsby-code-text\">FilterableProductTable</code>), так и снизу вверх (с маленького <code class=\"gatsby-code-text\">ProductRow</code>). Более простые приложения удобнее начать с компонентов, находящихся выше по иерархии. В более сложных приложениях удобнее в первую очередь создавать и тестировать подкомпоненты.</p>\n<p>В конце этого шага у вас на руках появится библиотека повторно используемых компонентов, отображающих вашу модель данных. Так как это статическое приложение, компоненты будут иметь только методы <code class=\"gatsby-code-text\">render()</code>. Компонент выше по иерархии (<code class=\"gatsby-code-text\">FilterableProductTable</code>) будет передавать модель данных через пропсы. Если вы внесёте изменения в базовую модель данных и снова вызовете <code class=\"gatsby-code-text\">ReactDOM.render()</code>, то пользовательский интерфейс отразит эти изменения. Вы можете увидеть, как обновляется интерфейс и где следует сделать очередные изменения. Благодаря <strong>одностороннему потоку данных</strong> (или <em>односторонней привязке</em>), код работает быстро, но остаётся понятным. </p>\n<p>Если у вас остались вопросы по выполнению данного шага, обратитесь к <a href=\"/docs/\">документации React</a>.</p>\n<h3 id=\"a-brief-interlude-props-vs-state\"><a href=\"#a-brief-interlude-props-vs-state\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Небольшое отступление: чем пропсы отличаются от состояния </h3>\n<p>Существует два типа «модели» данных в React: пропсы и состояние. Важно, чтобы вы понимали разницу между ними, иначе обратитесь к <a href=\"/docs/state-and-lifecycle.html\">официальной документации React</a>. Посмотрите также раздел <a href=\"/docs/faq-state.html#what-is-the-difference-between-state-and-props\">Какая разница между state и props?</a></p>\n<h2 id=\"step-3-identify-the-minimal-but-complete-representation-of-ui-state\"><a href=\"#step-3-identify-the-minimal-but-complete-representation-of-ui-state\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Шаг 3: Определим минимальное (но полноценное) отображение состояния интерфейса </h2>\n<p>Чтобы сделать наш UI интерактивным, нужно, чтобы модель данных могла меняться со временем. В React это возможно с помощью <strong>состояния</strong>.</p>\n<p>Чтобы правильно построить приложение, сначала нужно продумать необходимый набор данных изменяемого состояния. Главное тут следовать принципу разработки <a href=\"https://ru.wikipedia.org/wiki/Don%E2%80%99t_repeat_yourself\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">DRY: <em>Don’t Repeat Yourself</em> (рус. не повторяйся)</a>. Определите минимально необходимое состояние, которое нужно вашему приложению, всё остальное вычисляйте при необходимости. Например, если вы создаёте список дел, держите массив пунктов списка под рукой — но не стоит хранить отдельное состояние для количества дел в списке. Если надо отобразить количество элементов — используйте длину существующего массива.</p>\n<p>Давайте перечислим все данные в нашем приложении. У нас есть:</p>\n<ul>\n<li>Первоначальный список товаров.</li>\n<li>Поисковый запрос, введённый пользователем.</li>\n<li>Значение чекбокса.</li>\n<li>Отфильтрованный список товаров.</li>\n</ul>\n<p>Давайте рассмотрим данные по частям и определим, что должно храниться в состоянии. Задайте себе три вопроса:</p>\n<ol>\n<li>Передаются ли они от родителя через пропсы? Если так, тогда эти данные не должны храниться в состоянии компонента.</li>\n<li>Остаются ли они неизменными со временем? Если так, тогда их тоже не следует хранить в состоянии.</li>\n<li>Можете ли вы вычислить их на основании любых других данных в своём компоненте или пропсов? Если так, тогда это тоже не состояние.</li>\n</ol>\n<p>Исходный список товаров передаётся через пропсы, так что не нужно хранить его в состоянии компонента. Поисковый запрос и состояние чекбокса изменяются со временем, и их нельзя вычислить из других данных, так что они вполне сойдут за состояние. Напоследок, отфильтрованный список товаров не является состоянием, так как его можно вычислить из оригинального списка, поискового запроса и значения чекбокса.</p>\n<p>В итоге, состоянием являются:</p>\n<ul>\n<li>Поисковый запрос, введённый пользователем</li>\n<li>Значение чекбокса</li>\n</ul>\n<h2 id=\"step-4-identify-where-your-state-should-live\"><a href=\"#step-4-identify-where-your-state-should-live\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Шаг 4: Определим, где должно находиться наше состояние</h2>\n<p data-height=\"600\" data-theme-id=\"0\" data-slug-hash=\"qPrNQZ\" data-default-tab=\"js\" data-user=\"lacker\" data-embed-version=\"2\" class=\"codepen\">Пример кода <a href=\"https://codepen.io/gaearon/pen/qPrNQZ\">Философия React: Шаг 4</a> на <a href=\"https://codepen.io\">CodePen</a>.</p>\n<p>Итак, мы определили минимальный набор состояний приложения. Далее нам нужно выяснить, какой из компонентов <em>владеет</em> состоянием или изменяет его.</p>\n<p>Помните: в React поток данных односторонний и сходит сверху вниз в иерархическом порядке. Сначала может быть не совсем ясно, какой из компонентов какое состояние должен хранить. <strong>На этом этапе новички спотыкаются чаще всего.</strong> Чтобы разобраться, следуйте этим инструкциям:</p>\n<p>Для каждой части состояния в приложении:</p>\n<ul>\n<li>Определите компоненты, которые рендерят что-то исходя из этого состояния.</li>\n<li>Найдите общий главенствующий компонент (компонент, расположенный над другими компонентами, которым нужно это состояние). </li>\n<li>Либо общий главенствующий компонент, либо любой компонент, стоящий выше по иерархии, должен содержать состояние.</li>\n<li>Если вам не удаётся найти подходящий компонент, то создайте новый исключительно для хранения состояния и разместите его выше в иерархии над общим главенствующим компонентом.</li>\n</ul>\n<p>Давайте применим эту стратегию на примере нашего приложения:</p>\n<ul>\n<li>Задача <code class=\"gatsby-code-text\">ProductTable</code> — отфильтровать список товаров, основываясь на состоянии, а <code class=\"gatsby-code-text\">SearchBar</code> — отобразить состояние для поискового запроса и чекбокса.</li>\n<li>Общий главенствующий компонент для обоих — <code class=\"gatsby-code-text\">FilterableProductTable</code>.</li>\n<li>По идее, имеет смысл содержать текст фильтра и значение чекбокса в <code class=\"gatsby-code-text\">FilterableProductTable</code>.</li>\n</ul>\n<p>Итак, мы приняли решение расположить наше состояние в <code class=\"gatsby-code-text\">FilterableProductTable</code>. Первое, что нужно сделать — добавить свойство <code class=\"gatsby-code-text\">this.state = {filterText: &#39;&#39;, inStockOnly: false}</code> в конструктор <code class=\"gatsby-code-text\">FilterableProductTable</code>, чтобы отобразить начальное состояние нашего приложения. После этого передайте <code class=\"gatsby-code-text\">filterText</code> и <code class=\"gatsby-code-text\">inStockOnly</code> в <code class=\"gatsby-code-text\">ProductTable</code> и <code class=\"gatsby-code-text\">SearchBar</code> через пропсы. Напоследок, используйте пропсы для фильтрации строк в <code class=\"gatsby-code-text\">ProductTable</code> и определения значений полей формы <code class=\"gatsby-code-text\">SearchBar</code>.</p>\n<p>Вы заметите изменения в поведении вашего приложения: задайте значение <code class=\"gatsby-code-text\">&quot;ball&quot;</code> для <code class=\"gatsby-code-text\">filterText</code> и обновите страницу. Вы увидите соответствующие изменения в таблице данных.</p>\n<h2 id=\"step-5-add-inverse-data-flow\"><a href=\"#step-5-add-inverse-data-flow\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Шаг 5: Добавим обратный поток данных </h2>\n<p data-height=\"600\" data-theme-id=\"0\" data-slug-hash=\"LzWZvb\" data-default-tab=\"js,result\" data-user=\"rohan10\" data-embed-version=\"2\" data-pen-title=\"Thinking In React: Step 5\" class=\"codepen\">Пример кода <a href=\"https://codepen.io/gaearon/pen/LzWZvb\">Философия React: Шаг 5</a> на <a href=\"https://codepen.io\">CodePen</a>.</p>\n<p>Пока что наше приложение рендерится в зависимости от пропсов и состояния, передающихся вниз по иерархии. Теперь мы обеспечим поток данных в обратную сторону: наша задача сделать так, чтобы компоненты формы в самом низу иерархии обновляли состояние в <code class=\"gatsby-code-text\">FilterableProductTable</code>.</p>\n<p>Поток данных в React — однонаправленный. Это помогает понять, как работает приложение, но нам потребуется немного больше кода, чем с традиционной двусторонней привязкой данных.</p>\n<p>Если вы попытаетесь ввести текст в поле поиска или установить флажок в чекбоксе данного примера, то увидите, что React игнорирует любой ввод. Это закономерно, так как ранее мы приравняли значение пропа <code class=\"gatsby-code-text\">value</code> в <code class=\"gatsby-code-text\">input</code> к <code class=\"gatsby-code-text\">state</code> в <code class=\"gatsby-code-text\">FilterableProductTable</code>.</p>\n<p>Давайте подумаем, как мы хотим изменить поведение. Нам нужно, чтобы при изменениях поисковой формы менялось состояние ввода. Так как компоненты должны обновлять только относящееся к ним состояние, <code class=\"gatsby-code-text\">FilterableProductTable</code> передаст колбэк в <code class=\"gatsby-code-text\">SearchBar</code>. В свою очередь, <code class=\"gatsby-code-text\">SearchBar</code> будет вызывать этот колбэк каждый раз, когда надо обновить состояние. Чтобы получать уведомления об изменениях элементов формы, мы можем использовать событие <code class=\"gatsby-code-text\">onChange</code>. Колбэки, переданные из компонента <code class=\"gatsby-code-text\">FilterableProductTable</code>, вызовут <code class=\"gatsby-code-text\">setState()</code>, и приложение обновится.</p>\n<h2 id=\"and-thats-it\"><a href=\"#and-thats-it\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Вот и всё </h2>\n<p>Надеемся, что этот пример поможет вам получить представление о том, как подойти к созданию компонентов и приложений в React. Хотя этот процесс и использует немного больше кода, помните, что код читают чаще, чем пишут. А модульный и прямолинейный код читается значительно легче. Когда вы начнёте создавать большие библиотеки компонентов, вы сможете по-настоящему оценить прямолинейность и связанность React, а повторно используемые компоненты сделают ваш код намного меньше. :)</p>","frontmatter":{"title":"Философия React","next":null,"prev":"composition-vs-inheritance.html"},"fields":{"path":"content/docs/thinking-in-react.md","slug":"docs/thinking-in-react.html"}}},"pageContext":{"slug":"docs/thinking-in-react.html"}},"staticQueryHashes":[]}