Comments 35
Спасибо, все структурировалось в моей голове.
Вся соль, в функции Render и в том, что state — это не часть компонента, как мне кажется. Вот именно это место и полностью мне объяснило всю соль flux. Еще раз спасибо.
Вся соль, в функции Render и в том, что state — это не часть компонента, как мне кажется. Вот именно это место и полностью мне объяснило всю соль flux. Еще раз спасибо.
+1
Но, насколько я понимаю, выносим за пределы компонента только то состояние, те данные, которые необходимо изменять на сервере.
И да, PS в статье я прочитал. :)
И да, PS в статье я прочитал. :)
0
state все таки относится именно к компоненту, и именно state однозначно определяет как будет отрисован компонент.
За пределы мы выносим не state, а данные, и в нужный момент просто копируем эти данные(из store) в state
За пределы мы выносим не state, а данные, и в нужный момент просто копируем эти данные(из store) в state
+1
Да, запутался я в терминах. И данные и state под одну гребенку запихал. Перечитал свой коммент, понял, что написано не то, что я хотел сказать. И да, Вы абсолютно правы.
0
Вы хотели сказать props вместо state.
0
нет, я хотел сказать, именно, state. props это список параметров пришедших в компонент из вне(от родителя), а state набор параметров описывающий именно внутренее состояние компоненета
+2
А вот и зря вы используете state. Flux создан для предотвращения непонятных изменений данных, и именно благодаря props мы можем декларативно объявлять компоненты и обновлять их основываясь на данных которые хранятся ВНЕ компонента. Тем самым имя куда более предсказуемые и чистые функции, нежели с каким-то магическим внутренним состоянием
0
Кстати, я ошибаюсь, или подход с тем, что мы не следим за тем, как именно изменился State возможен только в ReactJS, за счет виртуального DOM'a?
Точнее можно везде делать полную перерисовку, но только ReactJS позволяет это делать без просадки рендеринга.
Точнее можно везде делать полную перерисовку, но только ReactJS позволяет это делать без просадки рендеринга.
0
Скорее так, React полностью «перерисовывает» только виртуальный DOM, а реальный DOM трогаем по минимуму.
Выигрыш в скорости за счет того, что и новую версию виртуального DOM он сравнивает не реальным, а с предыдущей версией виртуального.
Выигрыш в скорости за счет того, что и новую версию виртуального DOM он сравнивает не реальным, а с предыдущей версией виртуального.
0
Стоит ещё заглянуть в комментарии к оригинальной статье, там разработчики из фэйсбука отвечают на некоторые вопросы:
blog.andrewray.me/flux-for-stupid-people/#comment-1819956843
blog.andrewray.me/flux-for-stupid-people/#comment-1819956843
+1
Да, комментарии стоящие.
Позволю себе перевести один из них.
Я работаю над Atlas в Facebook и использую React+Flux уже полтора года, так что могу ответить на некоторые вопросы:
— Как отправлять данные на сервер и обратно?
Отправка данных на сервер: Action Creator делает асинхронный запрос к серверу и, как только получен success или failure результат, посылает Action с соотвествующей информацией в Dispatcher, а затем обновляются и Store. Впрочем, Action Creator может послать Action не дожидаясь ответа от сервера, предполагая оптимистичный исход.
Получение данных от сервера: когда вы запрашиваете данные из Store, он может начать загружать данные в бекграунде и проинформировать вас, как только они получены. Store может быть синхронным, в этом случае getBlah() возвращает null если данные не были загружены, или асинхронным, тогда getBlah() возвращает Promise.
— Как управлять связью между компонентами не имеющими общего родителя?
Используйте Actions и Stores — они глобальны и могут использоваться любыми компонентами.
Позволю себе перевести один из них.
Я работаю над Atlas в Facebook и использую React+Flux уже полтора года, так что могу ответить на некоторые вопросы:
— Как отправлять данные на сервер и обратно?
Отправка данных на сервер: Action Creator делает асинхронный запрос к серверу и, как только получен success или failure результат, посылает Action с соотвествующей информацией в Dispatcher, а затем обновляются и Store. Впрочем, Action Creator может послать Action не дожидаясь ответа от сервера, предполагая оптимистичный исход.
Получение данных от сервера: когда вы запрашиваете данные из Store, он может начать загружать данные в бекграунде и проинформировать вас, как только они получены. Store может быть синхронным, в этом случае getBlah() возвращает null если данные не были загружены, или асинхронным, тогда getBlah() возвращает Promise.
— Как управлять связью между компонентами не имеющими общего родителя?
Используйте Actions и Stores — они глобальны и могут использоваться любыми компонентами.
+4
Ещё один стоящий комментарий, на этот раз из facebook/flux репозитория на github:
Пример чат-приложения я подготовил специально для конференции ForwardJS осенью 2014 года…
… мы хотели показать вызов серверного API из Action Creators, как это предпочитает делать Jing (автор Flux). Однако, внутри FB многие обычно делают запросы к серверу непосредственно из Store. Я считаю оба эти способа корректыми и не отдаю предпочтения какому либо из них.
Одно из преимуществ обращаться к серверу в Action Creator, а не в Store, это обработка ошибок.
Пример чат-приложения я подготовил специально для конференции ForwardJS осенью 2014 года…
… мы хотели показать вызов серверного API из Action Creators, как это предпочитает делать Jing (автор Flux). Однако, внутри FB многие обычно делают запросы к серверу непосредственно из Store. Я считаю оба эти способа корректыми и не отдаю предпочтения какому либо из них.
Одно из преимуществ обращаться к серверу в Action Creator, а не в Store, это обработка ошибок.
0
Сложилось впечатление, что фейсбуковцы переизобрели велосипед. Посмотрите на подход рендеринга Ember.js или динамический рендеринг Joosy. Он делает абсолютно то же самое, только прозрачно для пользователя: bind и dispatch магически происходят внутри фреймворков.
Единственный принципиальный плюс в решении от FB — это рендеринг через React с виртуальным DOM, и тот под глубоким сомнением. Насколько реально широк тот кейс, когда данные меняются, но не меняется отображение? И реально ли такая оптимизация _заметна_ пользователю, или её можно заметить только профайлером?
Единственный принципиальный плюс в решении от FB — это рендеринг через React с виртуальным DOM, и тот под глубоким сомнением. Насколько реально широк тот кейс, когда данные меняются, но не меняется отображение? И реально ли такая оптимизация _заметна_ пользователю, или её можно заметить только профайлером?
+1
Из-за декларативности компонент/шаблонов React выигрыш огромен. Вам не нужно определять все состояния компонента и переходы между ними. При увеличении сложности это значительно упрощает поддержку.
+2
Чем шаблоны React декларативнее шаблонов Ember?
Чтобы не быть голословным, я взял пример кода "A Stateful Component" с официального сайта React и реализовал его на Ember: emberjs.jsbin.com/figobe/edit?js,output Как видите, всё то же самое, только на два года раньше, чем React. ;)
React я не пробовал, но полагаю, что двусторонний data-binding и самовычисляемые свойства (computed properties, аналог нативных `get` и `set`, но со встроенным кешированием и автоматическим пересчитыванием при изменении зависимых свойств) избавляют от необходимости писать массу вспомогательного кода, который приходится писать в React.
Я уже не говорю про то, что если вы выбрали React, вам нужно самому позаботиться о Model, Controller, Router, Adapter и т. д… Код, соответствующий указанным слоям, есть в каждом приложении, просто не везде он вынесен в самостоятельные сущности. В лучем случае, вы надергаете зоопарк разнообразных библиотек и будете жирно смазывать их glue code'ом, чтобы заставить их работать друг с другом. В худшем, будете изобретать велосипеды.
Чтобы не быть голословным, я взял пример кода "A Stateful Component" с официального сайта React и реализовал его на Ember: emberjs.jsbin.com/figobe/edit?js,output Как видите, всё то же самое, только на два года раньше, чем React. ;)
React я не пробовал, но полагаю, что двусторонний data-binding и самовычисляемые свойства (computed properties, аналог нативных `get` и `set`, но со встроенным кешированием и автоматическим пересчитыванием при изменении зависимых свойств) избавляют от необходимости писать массу вспомогательного кода, который приходится писать в React.
Я уже не говорю про то, что если вы выбрали React, вам нужно самому позаботиться о Model, Controller, Router, Adapter и т. д… Код, соответствующий указанным слоям, есть в каждом приложении, просто не везде он вынесен в самостоятельные сущности. В лучем случае, вы надергаете зоопарк разнообразных библиотек и будете жирно смазывать их glue code'ом, чтобы заставить их работать друг с другом. В худшем, будете изобретать велосипеды.
+2
Посмотрел следующий пример с офсайта React:
В Ember это выглядело бы так:
Как говорится, без комментариев.
Я уже не говорю о том, что объявлять функцию внутри функции — это не очень хороший стиль программирования. Не ожидал такое увидеть на титульной странице флагманского open source продукта Facebook. :P
render: function() {
var createItem = function(itemText) {
return <li>{itemText}</li>;
};
return <ul>{this.props.items.map(createItem)}</ul>;
}
В Ember это выглядело бы так:
<ul>
{{#each item in items}}
<li>{{item}}</li>
{{/each}}
</ul>
Как говорится, без комментариев.
Я уже не говорю о том, что объявлять функцию внутри функции — это не очень хороший стиль программирования. Не ожидал такое увидеть на титульной странице флагманского open source продукта Facebook. :P
+1
У вас другая вера.
0
>>объявлять функцию внутри функции — это не очень хороший стиль программирования
вы точно про JS говорите?
вы точно про JS говорите?
+1
Единственный разумный повод объявлять функцию внутри функции — это создать замыкание или ограничить scope. В данном случае не происходит ни того, ни другого.
Это:
следовало записать так:
Я тут протестировал, разница в производительности — двукратная: jsperf.com/sibling-functions-vs-nested-functions
Не говоря уже о разнице в сложности структуры кода (и, соответственно, читаемости), а также наличии/отсутствии возможности юнит-тестирования функции
Это:
render: function() {
var createItem = function(itemText) {
return <li>{itemText}</li>;
};
return <ul>{this.props.items.map(createItem)}</ul>;
}
следовало записать так:
createItem: function(itemText) {
return <li>{itemText}</li>;
},
render: function() {
return <ul>{this.props.items.map(this.createItem)}</ul>;
}
Я тут протестировал, разница в производительности — двукратная: jsperf.com/sibling-functions-vs-nested-functions
Не говоря уже о разнице в сложности структуры кода (и, соответственно, читаемости), а также наличии/отсутствии возможности юнит-тестирования функции
createItem
.+2
Ну как минимум замыканий достаточно для того, чтобы не говорить что объявлять функции внутри функций — не очень хороший стиль программирования.
Что же до того, как записан код в примере, предполагаю, что так сделано намеренно, ибо это позволяет держать под контролем (в поле зрения) доступные для рендера функции внутри одного скоупа, и не смешивать с остальными методами вьюшки, что улучшает «понимаемость»
А за тест спасибо, возьму на вооружение
Что же до того, как записан код в примере, предполагаю, что так сделано намеренно, ибо это позволяет держать под контролем (в поле зрения) доступные для рендера функции внутри одного скоупа, и не смешивать с остальными методами вьюшки, что улучшает «понимаемость»
А за тест спасибо, возьму на вооружение
0
Да, клево, выглядит короче. Но все портит магия эмбера. Когда пробрасываются контексты их родительских контроллеров\вьюх\роутеров, и понять откуда появилась конкретная переменная — нет никакой возможности. Даже если дебажить — цикл рендера эмбера превращает дебаг в ад.
0
В современном Ember вместо Views и Controllers используются Components, которые имеют сугубо изолированный scope.
0
Так этот современный эмбер уже вышел или нет? Так-то компоненты были и до 2й версии, и ими я хоть как-то мог осмысленно пользоваться среди ужаса и боли наследованных\перенаследованных скоупов
0
Единственное, чего еще нет, это возможности из route передавать управление сразу в component, минуя view и controller. Эта возможность запланирована на версию 1.12 (недавно вышли 1.10 и 1.11beta).
На данный момент для каждого route создается по view и controller. Но о них можно спокойно забыть и передавать данные сразу в компоненты через шаблон.
На данный момент для каждого route создается по view и controller. Но о них можно спокойно забыть и передавать данные сразу в компоненты через шаблон.
0
объявлять функцию внутри функции — это не очень хороший стиль программирования
Можно поподробней? Например:
def joinPaths(*args):
def preparePathPart(part): # prepare path parts to be joined by join method
# trim slashes from the end
# etc
def joinParts(paths, delimiter='/'): # another function inside of a function, join works only with prepared data
return args.join(delimiter)
return joinParts( map(args, preparePathPart) )
>>> joinPaths('/etc/', 'init.d/', 'some.conf')
'/etc/init.d/some.conf'
P.S. это просто синтетический пример на python-like псевдо-языке
Я не понимаю, какие конкретно могуть быть проблемы с тем, что я тут использовал аж 2 функции внутри joinPaths
Ровно то же самое я делаю не только на Python, но и на PHP/JS/Ruby/Go. Ни у меня, ни у моих коллег за долгие годы не было с этим никаких проблем. Более того, я считаю, что такая внутренняя декомпозиция хорошо структурирует функцию внутри самой функции. Неплохо было бы увидеть хорошее объяснение, почему это плохой стиль.
0
Кстати по коду может показаться, что вложенные ф-ии создаются при каждом запуске joinPaths, хотя в действительности этого не происходит (в случае с питоном), вложенные ф-ии уже «скомпилированы» до этого, к ним просто применяются разные «замкнутые» переменные, поэтому такой подход не должен повлиять на производительность (если кого это волнует).
0
За Python не скажу, а в JS разница в производительности 15-кратная: jsperf.com/externally-vs-internally-defined-function
0
UFO just landed and posted this here
Вся суть React в декларативности шаблонов. Компонент при каждом изменении полностью перерисовывается (но виртуально), затем React вычисляет минимально дешевую мутацию состояний из А в Б. В императивном подходе все мутации состояний нужно определять руками. При увеличесии сложности компонента возрастает сложности определения всех состояний и переходов. Соответсвенно возрастает риск ошибки и сложность понимания.
+4
Ваше хранилище будет реагировать на посланное событие:
и далее
ListStore.items.push( payload.newItem );
мне одному кажется, что тут хранилище никак не реагирует на сообщение, а как раз диспатчер?
т.е. разве не правильнее будет сделать как-то так:
ListStore.items_push( payload.newItem );
т.о. не диспатчер будет менять какое свойство в хранилище, а диспатчер будет посылать сообщение хранилищу, чтобы оно изменило себя.
0
Напоминает Windows с его перерисовкой только обновляемых частей окна.
Те же события.
Причём подобную событийную модель я давно использую в своих расширениях для браузеров.
Те же события.
Причём подобную событийную модель я давно использую в своих расширениях для браузеров.
0
Sign up to leave a comment.
Flux для глупых людей