Создание современных Web

приложений на основе Catbee 3.0.0

Catbee Core Concepts

- Изоморфный Javascript фреймворк

- Написан в ООП стиле с применением Service Locator Pattern и Dependency Injection
- Следует принципам Unidirectional Data Flow
- Предлагает W3C Web Components подход для слоя представления

Немного о интерфейсных приложениях

Отличия от других приложений:

 

- Конечное количество состояний UI

- HTML вместо JSON/XML/YAML/ETC...

- Ярковыраженная событийная система

Основные хранилища состояний

 

- URL

- Cookie/LocalStorage/SessionStorage/...

- DOM

- Javascript Memory

HTML. Какой он бывает?

// Самый простой элемент
<div></div>

// Интерактивный элемент
<input type="text" />

// Сложный Web Component с Shadow DOM
<input type="number">
  #shadow-root (user-agent)
  <div id="text-field-container" pseudo="-webkit-textfield-decoration-container">
    <div id="editing-view-port">
      <div id="inner-editor"></div>
    </div>
  </div>
  <div pseudo="-webkit-inner-spin-button" id="spin"></div>
</input>

HTML. Как его готовим мы?

<cat-button theme="blue" label="Заказать звонок">
  <button class="_button_6v0cw_1 _blue_1gav3_36">
    Заказать звонок
  </button>
</cat-button>

HTML. Как его готовим мы?

this.$context.createComponent('button', { 
  constructor: Button,
  props: {
    label: 'Заказать звонок',
    theme: 'blue'
  }
})
.then((element) => {
  // Element is:
  // <cat-button>
  //   <button class="_button_6v0cw_1 _blue_1gav3_36">
  //     Заказать звонок
  //   </button>
  // </cat-button>
});

Unidirectional Data Flow

Может быть знаком как CQRS + Event Sourcing

Data Flow Diagram

Пример сигнала

exports.basicSignal = [
  setPageTitle,
  setPageDescription
]

function setPageTitle (args, state) {
  state.set(['page', 'title'], 'account.2gis.ru - очень крутой');
}

function setPageDescription (args, state) {
  state.set(['page', 'description'], 'Все разработчики ЛК няши! :meow:')
}

Пример сигнала

exports.advancedSignal = [
  setLoading, // Sync function
  [ // Here we run parallel functions
    getUser, { // Async function with 2 outputs success and error
      success: [setUser], // Run if we call output.success in getUser
      error: [setUserError] // Run if we call output.error in getUser
    },
    getNews, { // It's function will run paraller with getUser, like Promise.all
      loaded: [setNews],
      error: [setNewsError]
    }
  ],
  unsetLoading
]

function getUser (args, state, output) {
 ajax.get('/url')
  .then(function (response) {
    output.success({ news: response });
  }
  .catch(function (response) {
    output.error({ error: response.code });
  })
}

Пример получения данных

// Child component
class Component {
  render () {
   return this.$context.getWatcherData().then((data) => data));
  }
}

...

// Parent component
module.exports = { 
  constructor: Parent,
  children: [
    {
      name: 'child',
      component: child,
      watcher: {
        value: ['path', 'to', 'value']
      }
    }
  ]
}

Computed Fields

Computed Fields

state.set(['counter'], Baobab.monkey(
 ['todos'], 
 (todos = []) => {
   return todos.filter((todo) => todo.status == 'active').length)
 }
);

Computed Fields

state.set(['auction', 'UIState', 'isBidsButtonEnabled'], Baobab.monkey(
 ['permissions', 'adverts', 'bids'],
 ['auction', 'campaign', 'permissions', 'isAgreementAccepted'],
 ['auction', 'computed', 'isBidsChanged'],
 ['auction', 'computed', 'isBidsValid'] 
 (isBidsEnabled, isAgreementEnabled, isBidsChanged, isBidsValid) => 
   _.every([isBidsEnabled, isAgreementEnabled, isBidsChanged, isBidsValid])
));

Вопросы?

deck

By Kirill Kaysarov