Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Егор Банщиков

FrontFest
November 27, 2017

Егор Банщиков

FrontFest

November 27, 2017
Tweet

More Decks by FrontFest

Other Decks in Programming

Transcript

  1. Animator this.state = { currentY: undefined, finishY: undefined } <div

    style={{ transform: `translate3d(0, ${this.state.currentY}px, 0)` }} /> Делаем анимацию на React export class extends React.Component() { constructor(props) { super(props); } render() { return ( ) } } 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12.
  2. <div style={{ transform: `translate3d(0, ${this.state.currentY}px, 0)` }} /> onTouchStart={this._onStart} onTouchMove={this._onMove}

    onTouchEnd={this._onEnd} </div> _onStart this.setState({ currentY, finishY }); _onMove this.setState({ currentY }); render() { return ( ) } = () => { let finishY; let currentY; // рассчитываем стартовую и конечную позицию по оси OY } = () => { let currentY; // рассчитываем текущую позицию блока по оси OY } 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22.
  3. <div style={{ transform: `translate3d(0, ${this.state.currentY}px, 0)` }} /> onTouchStart={this._onStart} onTouchMove={this._onMove}

    onTouchEnd={this._onEnd} </div> _onStart this.setState({ currentY, finishY }); _onMove this.setState({ currentY }); <div ref={(el) => this.container = el} /> onTouchStart={this._onStart} onTouchMove={this._onMove} onTouchEnd={this._onEnd} </div> _onStart _onMove this.container.style.transform = `translate3d(0, ${this.currentY}px, 0)` Было render() { return ( ) } = () => { let finishY; let currentY; // рассчитываем стартовую и конечную позицию по оси OY } = () => { let currentY; // рассчитываем текущую позицию блока по оси OY } Стало componentDidMount() { this.finishY = this._getFinishY(); this.currentY = this._getCurrentY(); } render() { return ( ) } = () => { // Добавьте код по вкусу } = () => { this.currentY = this._getCurrentY(); // рассчитываем текущую позицию блока по оси OY } 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24.
  4. _onEnd _moveAnimator 1 — setTimeout(() => this._moveAnimator(callback), 1000 / 60)

    2 — requestAnimationFrame(() => this._moveAnimator(callback) = () => this._moveAnimator(this._finishAnimation) = (callback) => { while (this.finishY - this.currentY !== 0) { // доводим события до нужной точки по ОСИ OY } callback() } 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11.
  5. // СТУЛ-1 ЧЕРВИ ПИКИ // СТУЛ-2 ЧЕРВИ ПИКИ const st

    = document.querySelector('#chairs .st'); const raf = document.querySelector('#chairs .raf'); st.addEventListener('click', () => { setTimeout(() => st.innerHTML = , 0); st.innerHTML = ; }); raf.addEventListener('click', () => { requestAnimationFrame(() => raf.innerHTML = ); raf.innerHTML = ; }); СТУЛ 1 СТУЛ 2
  6. Коротко о scroll • На мобилках скроллят чаще • На

    мобилках событие скролл срабатывает чаще
  7. Итоги первой части • Жизненный цикл фрейма • Менеджмент слоев

    • will-change • 60fps анимация • requestAnimationFrame vs setTimeout • О скролле
  8. jsxExample() hyperScriptExample() h(nodeName, attributes, children) Что такое jsx? export function

    { return ( <div id='Hello'> Hello! <br /> </div> ); }; export function { return h('div#hello', undefined, [ 'Hello', h('br') ]); }; function { return { nodeName, attributes, ...children} }; 01. 02. 03. 04. 05. 06. 07. 08. 01. 02. 03. 04. 05. 06. 01. 02. 03.
  9. hyperScriptExample() h(nodeName, attributes, children) vNode export function { return h('div#hello',

    undefined, [ 'Hello', h('br') ]); }; function { return { nodeName, attributes, ...children} }; export const = { nodeName: 'div', attributes: { id: 'hello' } children: [ 'Hello', { nodeName: 'br' } ] }; 01. 02. 03. 04. 05. 06. 01. 02. 03. 01. 02. 03. 04. 05. 06. 07. 08.
  10. render(vNode) Vnode -> Node export function { if (typeof vNode

    === 'string') { return document.createTextNode(vNode); } let node = document.createElement(vNode.nodeName); for (let name in Object.apply(vNode.attributes)) { let value = vNode.attributes[name] if (name in node) { node[name] = value; } else { node.setAttribute(name, value) } } for (let i =0; i < vNode.children.length; i++) { node.appendChild(render(vNode.children[i])); } return node }; 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 14. 15. 16. 17. 18.
  11. Итоги второй части • Что такое Preact • Как работает

    VirtualDom • Какие отличия у React и Preact
  12. Текущий app.js 1. Сторонние библиотеки — react, redux, lodash и.т.д.

    2. Полифилы, подключаемые в зависимости от условий 3. Код приложения
  13. Первый этап улучшений 1. Выносим сторонние библиотеки в отдельный файл

    — vendor.js 2. Добавляем хэш — 4d882c546d0ea4407c14.vendor.js 3. Выносим часто используемый код new webpack.optimize.CommonsChunkPlugin({ name: 'app', minChunks: 2, children: true }); 4. Профит 01. 02. 03. 04. 05.
  14. this.state = { Component: null } Второй этап улучшений export

    default class extends React.PureComponent { constructor(props) { super(props) } 01. 02. 03. 04. 05.
  15. this.state = { Component: null } if (!this.state.Component) { this.props.moduleProvider().then(

    ({Component}) => this.setState({ Component })); } Второй этап улучшений export default class extends React.PureComponent { constructor(props) { super(props) } componentDidMount() { } 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11.
  16. this.state = { Component: null } if (!this.state.Component) { this.props.moduleProvider().then(

    ({Component}) => this.setState({ Component })); } return <div>{ Component ? <Component /> : <Preloader /> }>/div> Второй этап улучшений export default class extends React.PureComponent { constructor(props) { super(props) } componentDidMount() { } render() { const { Component } = this.state; ); } }; 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 14. 15. 16. 17. 18.
  17. Второй этап улучшений import someModule from './dir/someModule.js'; const path =

    './dir/someModule.js'; import(path).then(someModule => someModule.foo()); const card = () => import('modules/card/container'); <LazyLoaderComponent moduleProvider={card}/> 01. 02. 03. 04. 05. 06. 07.
  18. Animal run() Human extends Animal cry() complain() askExistentialQuestions() isKindAndDecent() Пример

    Typescript class { public name: string; public age: number; public sizes: { weight: number; height: number }; private { /* do something */ } } class { /* плакаться */ private { return 'Я так больше не могу!'} /* жаловаться */ private { return 'Я устал, хочу домой!'} /* задать экзистенциальный вопрос */ private { return 'Где второй носок?!'} /* добрый и порядочный? */ private { return Math.random() < 0.05 ? 'да' : 'нет' } } 01. 02. 03. 04. 05. 06. 07. 01. 02. 03. 04. 05. 06. 07. 08. 09. 10.
  19. var __extends = (this && this.__extends) || (function () {

    var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var Animal = /** @class */ (function () { function Animal() { } Animal.prototype.run = function () { }; return Animal; }()); var Human = /** @class */ (function (_super) { __extends(Human, _super); function Human() { return _super !== null && _super.apply(this, arguments) || this; } Human.prototype.cry = function () { return 'Я так больше не могу!'; }; Human.prototype.complain = function () { return 'Я устал, хочу домой!'; }; Human.prototype.askExistentialQuestions = function () { return 'Где второй носок?!'; }; Human.prototype.isKindAndDecent = function () { return Math.random() < 0.05 ? 'да' : 'нет'; }; return Human; }(Animal)); 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27.
  20. Как .ts(x) в .js(x)? module: { rules: [ { test:

    /\.ts(x)?$/, use: [ { loader: 'ts-loader' } ] } ] }, 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12.
  21. PhotoViewerProps prevPhoto?: PhotoItem; nextPhoto?: PhotoItem; changePhoto: (photoId: string) => void;

    close: () => void; PhotoViewerState Typescript и React interface { total: number; photoSource?: string; copyrightCode: string; url: string; icon?: string; currentIndex: number; prevPhotoSeoLink?: string; nextPhotoSeoLink?: string; backLink: string; } interface { copyrightStore: { [name: string]: string }; } 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 14. 15. 16. 17. 18.
  22. class PhotoViewer extends React.Component<PhotoViewerProps & WithI18nProps, PhotoViewerState> { private prev:

    HTMLDivElement; // контейнер для предыдущей фотографии private next: HTMLDivElement; // контейнер для следующей фотографии private carousel: HTMLDivElement; // контейнер для всех фотографий (от 1 до 3) private width: number; // ширина экрана private delta: number; // разница между начальным и конечным значением драга по оси ОХ private startX: number; // начальная точка драга private startY: number; // начальная точка драга по вертикали ... private ptz: PinchToZoom; constructor(props: PhotoViewerProps & WithI18nProps) { super(props); this.state = { copyrightStore: {}, }; } } 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 14. 15. 16. 17.
  23. UserLoginAction LoginFields userLogin UserLoginAction Typescript и Redux export const USER_LOGIN

    = 'USER_LOGIN'; export interface { type: 'USER_LOGIN'; payload: LoginFields; async: true; } export interface { email: string; password: string; userId?: string; } export const = (payload: LoginFields): => ({ type: USER_LOGIN, payload, async: true }); 01. 02. 03. 04. 05. 01. 02. 03. 04. 05. 01. 02. 03. 04. 05.
  24. User UserAction User USER_FETCH_SEARCH_HISTORY_SUCCESS: USER_START_UP_SUCCESS: USER_LOGIN_SUCCESS: USER_GET_TOKENS_VIA_LOGIN_TOKEN_SUCCESS: USER_RECOVERY_PASSWORD_SUCCESS: USER_LOGOUT: export

    default function (state: = defaultState, action: ): { switch (action.type) { case // do something return newState; case // do something return newState; case // do something return newState; case // do something return newState; case // do something return newState; case // do something return newState; ...more 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21.
  25. UserAction export type = UserSetParams | UserFetchSearchHistorySuccessAction | UserSetUA |

    StoreLinkClick | UserUpdateOnlineStatus | UserAllowLocation | UserFollowLocation | UserSetLocation | UserLocationSuccess | UserLocationError | ... | UserLogout 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13.
  26. Итого • Как уменьшить лаги • Как сократить бандл •

    Как делить бандл • Как уменьшить число багов