Цитата:
Цитата:
Будь здоров, кушай торт, он полезен :) |
Есть две архитектуры flux(store, action, component, dispatcher). Одна зависима от другой. Это значит что пока 1 не обновиться, 2 не должен обновляться.
Как организовать внутри одного диспетчера я понимаю(ставим waitFor), а между двумя как построить взаимосвязь недогоняю. Как организовать эту зависимость с диспетчерами? |
Цитата:
Flux должен быть один. Dispatcher - тоже. http://fluxxor.com/images/flux-complex.png Хочу заметить, я перепробовал все способы и остановился на одном, как самом удобном. Он выделен красным. Почему он - расскажу в конце. 1. Асинхронные действия. Из action возвращаешь Promise. Когда он выполнится, выполняешь другое действие 2. waitFor. Это, можно сказать, сахар над Store.on('change'). Все просто - в хранилище A выполняешь waitFor('B', callback). Когда вызовится B.emit('change'), выполнится и переданный callback 3. Недокументированный API. Хранилища наследуются от EventEmitter. У него есть привычный всем метод once (колбек на один раз). 4. componentDidUpdate(prevProps, prevState) внутри Controller Component. Проверяем, изменились ли данные в новом состоянии. Если да - отсылаем action. Теперь обо всём по порядку. 1. Асинхронные действия добавляем в actions параметр callback, или возвращаем Promise. Это идет в разрез с идеей Flux. Это не стоит использовать (имхо) 2. waitFor waitFor мне неплохо вмазал (шо аж день не отпускало), так что, думаю, следует хорошо пояснить этот момент Я использовал Fluxxor, так что его и буду описывать. Документация по Store.waitFor Как вы видите, waitFor должен находиться внутри хранилища. Как тогда выполнить обновление с зависимостями? A - master Store B - slave Store Сналача, регистрируем обработчик изменения через вызов нужного action (напр. Flux.actions.b.waitForAUpdate) Далее, выполняем изменение хранилища A (напр. Flux.actions.a.setItem) И приходим к проблеме. Вызов этого дела выглядит так: Flux.actions.b.waitForAUpdate() Flux.actions.a.setItem('yolo') А проблема в том, что идеология Flux не разрешает отправлять больше одного действия одновременно (а они не обязательно синхронные -т.е. нельзя рассчитывать на это, и нужно надавить на реактивность) тут либо можно изгальнутся костылем, пустив обновление состояния A через таймаут: Flux.actions.b.waitForAUpdate() setTimeout( () => Flux.actions.a.setItem('yolo') ) либо вернуть из создателя действия (ActionCreator, лол) обещание, которое содержит в себе таймаут: Flux.actions.b.waitForAUpdate().then( () => Flux.actions.a.setItem('yolo') ) Исходник для Flux.actions.b.waitForAUpdate получается таким: Файл flux/actions/b.js: export default { waitForAUpdate() { return Promise.delay().then(() => this.dispatch('WAIT_FOR_A_STORE') ) }, } (Promise.delay - это нестандартный метод, из библиотеки bluebird) Для сравнения, создатель действия без обещания - такой: Файл flux/actions/b.js: export default { waitForAUpdate() { this.dispatch('WAIT_FOR_A_STORE') // и чё, кода действие выполнится то? }, } Если у вас крупное приложение, и действия отсылаются через таймауты, то у вас появятся проблемы, если вы будете использовать этот способ. 3. Недокументированный API. У нас ведь Flux, так? значит, все действия и хранилища видны всему. Вкратце - одноразово подписываемся на событие изменения, и из него уже дальше пляшем Flux.stores('A').once('change', () => { // хранилище изменило состояние const AState = Flux.stores('A').getState() Flux.actions.b.doSimethingWith(AState) }) Flux.actions.a.setItem('yolo') Наверное, это дело лучше красиво спрятать в ActionCreator, обернув обещанием. 4. componentDidUpdate(prevProps, prevState) Имхо, кажется костыльным и уродивым, но это похоже на самый хороший и добротный способ, с точки зрения асинхронной реактивности (имхо) Состояние хранилищ передается controller component, который расфасовывает полученные данные вниз по дереву компонентов через свойства (props) Fluxxor предоставляет сахарок для легкого подписывания на событие изменения хранилищ и перевод их состояний в состояние компонента. componentDidUpdate, как вы знаете, вызывается после того, как у компонента сменились свойства или состояние. Ну и измениться они могут, в случае controller component, из-за смены состояния одного из прослушиваемых хранилищ выглядит это так: A - master Store B - slave Store Пусть компонент копирует состояния хранилищ в пространства имен : // это - слушалка события 'change' у двух наших хранилищ onSomeStoreChanged() { const A = Flux.stores('A').getState() const B = Flux.stores('B').getState() return { A, B } } // состояние хранилища A будет в this.state.A // для B - соотв. отсылаем данные хранилищу A: Flux.actions.A.setItem('yolo') внутри CDU, если что-то изменилось, и это состояние хранилища А, то нужно обновить данные в В: componentDidUpdate(prevProps, prevState) { if (this.state.A !== prevState.A) { Flux.actions.b.updateFromItem(this.state.A.item) } } ну, или можно использовать CWU (цепочка реакций должна пойти быстрее): componentWillUpdate(nextProps, nextState) { if (this.state.A !== nextState.A) { Flux.actions.b.updateFromItem(nextState.A.item) } } А у нас цепочка зависимостей (A -> B -> C)? Тогда: componentWillUpdate(nextProps, nextState) { if (this.state.A !== nextState.A) { Flux.actions.b.updateFromItem(nextState.A.item) } if (this.state.B !== nextState.B) { Flux.actions.c.updateFromItem(nextState.B.item) } } Как-то так ... в общем, у нас есть перенос логики обновления в компоненты-контроллеры, но для Flux - это нормально (вроде) Почему лучше использовать CWU/CDU для цепочки событий? Все просто - действие (action), на момент выполнения этих методов, уже прошло круг от создателя действий до компонентов (напомню, только одно действие может обходить кружок в момент времени). waitFor обеспечивает такой же функционал (вызывается, когда хранилище заявило об изменении состояния), но как вызвать действие (Action) внутри хранилища (Store)? МБ дело вкуса, но я лучше не буду пихать всякие actions.yolo() внутри чистенького Store. Ну и еще - разделение логики обновления данных от самого обновления данных И еще - абстрагирование от того, сколько действие выполняется. Получается действительно реактивная система обмена данными Всё вышесказанное является огромнейшим ИМХО. Если есть предложения, буду рад их услышать. |
Ещё пометочка, но отдельным сообщением.
1. Для сравнений типа this.state.B !== nextState.B нужно, чтобы данные не были мутабельными (иммутабельность, короче) Это делается либо через _.cloneDeep, либо использованием билиотек, предоставляющих иммутабельные структуры данных Можно и проверять на предмет изменения объекта через _.isEqual(this.state.B, nextState.B), но спор иммутабельность vs мутабельность - отдельная тема 2. Controller component - шаблон проектирования компонентов. Заключается в том, чтобы выделить 2 компонента, которые по одиночке используют один Store и поставить над ними родителя, который содержит в себе получение данных из Flux и её передачу по дереву компонентов с помощью props. что-то типа такого (но тут не один Store, а два): http://2.bp.blogspot.com/-mSMHB7w43l...30.05%2BPM.png count_control и sold_flag_control берется из Flux и передается компонентам через props с именами Sold flag и Count |
|
Цитата:
|
Накой было резать html autocomplete?
|
Поскольку ангуляр достал своим DI, тормозами и прочим, решил ознакомиться с реактом. Вчера посмотрел видео, сегодня почитал доку и написал первый пример на es6 + React.
//Test.jsx class Test extends React.Component { render() { return ( <h1>test</h1> ); } } export default Test; //client.js import Test from './components/Test.jsx'; React.constructAndRenderComponent( Test, {}, document.getElementById('container') ); <!DOCTYPE html> <html> <head> <title>React Sandbox</title> <meta charset="utf-8"> <script src="lib/react.js"></script> </head> <body> <div id="container"></div> <script src="dist/sandbox.js"></script> </body> </html> результат https://yadi.sk/i/hrZgXP64gNiUf С документацией по 0.13.2, конечно, беда. Хочется, как в шаблонизаторе лепить ифы и фор_ичи, но нельзя :-E Как же быть? Смотрел в сторону react-templates, но не уверен. Цитата:
1. DI ангуляра не нужен, т.к. есть es6 модули 2. утилиты (forEach, isObject, etc) мне тоже не сдались, у меня свои 3. транспорт ангуляра (ajax) не требуется, у меня свой Т.о., если модели у меня свои, утилиты свои, свой транспорт, но ангуляр заставляет меня юзать его собственные и при этом тормозит... не хорошо это :) Да, с ним можно писать меньше кода. Декларативность нравится, но стоит ли оно того? По большому счету, теперь мне нужна только вьюха. |
Цитата:
Цитата:
Цитата:
Там сборка идет в рендере перед return render: function () { var i = 0; var imgs = this.props.list.length == 0 ? '' : this.props.list.map(function(item){ return <Photos src={item.img} title={item.name} key={'photo-' + (i++)} />; }); return ( <div className="imgs"> {imgs} </div> ); } |
Причем <Photos может состоять ещё из десятка компонентов или из одного <img>, это реально круто, наследование в html :)
|
Gozar,
чуть более кошеrный вариант) render() { let imgs = this.props.list.length == 0 ? '' : this.props.list.map(function(item, i) { return <Photos src={item.img} title={item.name} key={`photo-${i}`} />; }); return ( <div className="imgs"> {imgs} </div> ); } |
:)
|
Цитата:
Как вы опишите такую html структуру? Гляжу, есть вкусности для coffee-script. Хочется чего-нибудь подобного. |
блин ну и жестя, как вообще на нем писать??? О_О это ж слишком низкий уровень, как синхронить с моделями? как хранить данные? он же слишком низкоуровневый мать его, поверх него надо что то писать получается и уже на нем делать сайт?
|
nerv_,
Цитата:
Цитата:
UIjs, Цитата:
|
Gozar,
можешь рассказать, как у тебя устроено общение с сервером? Я сейчас Flux пытаюсь осилить и встал перед дилеммой - какая часть системы и когда начинает запрашивать исходные данные с сервера? |
я посмотрел видео разные щас и так и не понял чем он лучше юишки моей... (
обьясните в чем прорыв? у меня можно написать ui-scrollbar в атрибуте, и создастся кастомный красивый скроллбар. можно так в реакте сделать? |
Цитата:
похоже, альтернативы jade-react нет ппц) Для того, чтобы писать шаблоны для реакта, придется писать их на jade (судя по всему). или юзать react-templates вроде симпатичная штука Цитата:
Цитата:
Safort, хочешь сказать, ты шаблоны руками пишешь, без движков?) Это же ад) |
UIjs,
а я посмотрел твоё видео о твоей юишке и тоже ничего не понял :( |
Цитата:
Цитата:
|
nerv_,
Цитата:
|
Цитата:
|
UIjs,
Цитата:
|
Цитата:
--- В целом, я посмотрел/почитал про реакт, и оказалось что, не только я юзаю по всюду методы getState()/setState(), реакт тоже ими оперирует (понятиями состояния приложения). Единственное что, вводится еще термин иммутабельность данных (в рамках реакта). |
Цитата:
Цитата:
|
Цитата:
|
Цитата:
|
Цитата:
class Component extends React.Component { render() { let images = this.props.list.map(({img, name}, i) => ( <Photos src={img} title={name} key={i} /> )); return ( <div className="images"> {images} </div> ); } } Цитата:
Цитата:
Цитата:
|
Erolast, вот покажите например как в реакте сделать рекурсивное древо файловой системы например? а я покажу как на юишке)
|
Цитата:
Нужно чётко понимать что такое жизненный цикл. http://tftf.ru/stati/javascript/reac...and_lifecycle/ А ещё нужно знать что можно вешать прослушку на изменение хранилища: componentDidUpdate: function() { CommentsStore.addChangeListener(this._actionState); }, При изменении CommentsStore выполняем свою функцию this._actionState, которая обновляет комменты или что-то ещё делает... Цитата:
Разбивать на компоненты. В компонентах могут быть свои обработчики(модульность!). Цитата:
|
Хочу попробовать http://fluxxor.com/ в нём сахара больше. В чистом React сахара маловато и flux тяжело даётся.
|
Цитата:
Пример "рутового" шаблона простого приложения на ангуляре. Разумеется, внутри него есть другие компоненты. Просто верстать, просто читать, просто поддерживать. Аналогичного хочется и от реакта. <body> <div class="page"> <div ng-app="insider" class="insider"> <div ng-controller="insider.DefaultController" ng-cloak=""> <div ng-if="app.isReady"> <div class="insider__controls affix btn-group-vertical"> <div ng-repeat="config in app.tools track by config.id" ng-insider-node="config"></div> </div> <div class="insider__header"> <div class="container-fluid"> <div class="modes"> <div class="row"> <div class="col-4"> <h3>Mode</h3> <select ng-change="app.setModeById(app.model.modeId)" ng-model="app.model.modeId" ng-options="mode.id as mode.title for mode in app.dictionaries.modes" class="form-control"></select> </div> <div ng-show="app.isFilterMode()" class="col-4"> <h3>Presets</h3> <select ng-change="app.setPresetById(app.model.presetId)" ng-model="app.model.presetId" ng-options="preset.id as preset.title for preset in app.presets" class="form-control"></select> </div> <div class="col-4"> <h3>Chunk</h3> <select ng-change="app.searchAsync()" ng-model="app.pagination.itemsPerPage" ng-options="chunk.value as chunk.title for chunk in app.dictionaries.chunks" class="form-control"></select> </div> </div> </div> <div class="row"> <div class="col-7"> <div class="form-horizontal"> <div class="form-group"> <div class="col-2 control-label">List</div> <div class="col-10"> <select ng-change="app.setModeById(app.model.modeId)" ng-model="app.model.modeId" ng-options="mode.id as mode.title for mode in app.dictionaries.modes" class="form-control"></select> </div> </div> </div> </div> <div class="col-5 text-right"> Добро пожаловать, <a href="#">Админушка</a> <button class="btn btn-primary" style="margin-left: 15px;">Выход</button> </div> </div> </div> </div> <!-- ADDING DIALOG :: START --> <div ng-insider-dialog-adding="app.dialogs.adding" insider="app"></div> <!-- ADDING DIALOG :: END --> <!-- EDITING DIALOG :: START --> <div ng-insider-dialog-editing="app.dialogs.editing" insider="app"></div> <!-- EDITING DIALOG :: END --> <!-- EDITING MULTIPLE DIALOG :: START --> <div ng-insider-dialog-editing-multiple="app.dialogs.editingMultiple" insider="app"></div> <!-- EDITING MULTIPLE DIALOG :: END --> <!-- TABLE :: START --> <div> <table class="table table-hover insider-table"> <thead> <tr ng-if="app.isFilterMode()" class="active"> <th> <div class="btn btn-default btn-checkbox"> <label> <input ng-model="app.model.selectedAll" ng-change="app.toggleSelection()" type="checkbox"> </label> </div> </th> <th ng-repeat="field in app.fields track by field.id"> <label ng-bind-html-unsafe="field.title"></label> <div ng-repeat="config in field.filter track by config.id" ng-insider-node="config"></div> </th> <th></th> </tr> </thead> <tbody ng-hide="app.isPending"> <tr ng-repeat="record in app.records.getArray() track by record.atomId"> <td> <input type="checkbox" ng-model="record._isSelected" ng-change="app.setSelection(app.getSelection())"/> </td> <td ng-repeat="field in app.fields track by field.id"> <div ng-switch="field.isEditable"> <div ng-switch-when="true"> <div ng-if="!app.isCellEditing(record.id, $index)"> <div ng-repeat="config in field.reading track by config.id" ng-insider-node="config"></div> </div> <div ng-if="app.isCellEditing(record.id, $index)"> <div ng-repeat="config in field.editing track by config.id" ng-insider-node="config"></div> </div> <div ng-show="app.isCellSaving(record.id, $index)">Saving...</div> <button ng-click="app.toggleCellEditing(record.id, $index)" type="button">Edit</button> </div> <div ng-switch-when="false"> <div ng-repeat="config in field.reading track by config.id" ng-insider-node="config"></div> </div> </div> </td> <td> <button ng-click="app.toggleFavorite(record.id)" type="button" class="hidden-button"> <span ng-show="app.isFavorite(record.id)" class="favorite glyphicon glyphicon-star"></span> <span ng-hide="app.isFavorite(record.id)" class="favorite glyphicon glyphicon-star-empty"></span> </button> <button ng-click="app.openEditingDialog(record.id)" type="button">Edit record</button> </td> </tr> </tbody> </table> <div ng-show="app.isPending"> <p>Loading…</p> </div> </div> <!-- TABLE :: END --> <div class="container-fluid text-right"> <!-- PAGINATION :: START --> <div ng-insider-pagination="app.pagination"></div> <!-- PAGINATION :: END --> </div> </div> </div> </div> </div> </body> Цитата:
Цитата:
Цитата:
|
Цитата:
В реакте я работаю с компонентами, а не какими-то div-ами и шаблонами из каши html разметки. Ты же сам хвалил web-components и после этого кидаешь шаблон-кашу и говоришь что это хорошо. В то время как реакт гораздо ближе к web-components чем эта жесть. Цитата:
Ты похоже ещё не понял, что такое React и в чём его основная фишка. |
Шаблон в реакт разбивается на компоненты, например:
Основной, верхнего уровня: <TodoApp> <Header> <TodoTextInput /> <MainSection> <ul> <TodoItem /> </ul> </MainSection> </TodoApp> Далее делим на: <MainSection> <ul> <TodoItem /> </ul> </MainSection> И только на самом примитивном уровне будет <div className="blabla">{this.props.name}</div> Думай компонентами, а не шаблонами! |
Цитата:
|
Цитата:
|
Цитата:
Цитата:
Цитата:
|
nerv_,
Цитата:
|
а вот результат https://www.youtube.com/watch?v=-TuhDVsoKYE
|
Цитата:
Цитата:
JSX - это по сути JS+XML, поэтому и более абстрактен и компоненты там в "html" выглядят как компоненты, а не как div-ы на которые сверху навешана гора атрибутов(Я ещё в fj понял, что получается каша если идти дорогой атрибутов, поэтому и свернул работы.). |
Часовой пояс GMT +3, время: 22:19. |