Slide 1

Slide 1 text

React Reconciler Как написать собственный рендерер HolyJS Moscow 2020

Slide 2

Slide 2 text

Ярослав Лосев LosYear github.com/losyear twitter.com/losyear Redis, креативное агентство

Slide 3

Slide 3 text

React Figma react-figma.dev github.com/react-figma @ilialesik @losyear

Slide 4

Slide 4 text

О чем поговорим? React Reconciler React → DOM Figma & Figma API React → Figma Итоги

Slide 5

Slide 5 text

О чем поговорим? React Reconciler React → DOM Figma & Figma API React → Figma Итоги

Slide 6

Slide 6 text

import React from ‘react’; import ReactDOM from ‘react-dom’;

Slide 7

Slide 7 text

Reconciler hostConfig Набор функций, специфичных для среды отрисовки. Например, как создать или изменить узел. Модуль react-reconciler с npm. Является общим для всех отрисовщиков

Slide 8

Slide 8 text

Reconciler • UI agnostic • Находит изменения дерева элементов • Передает найденные изменения отрисовщику

Slide 9

Slide 9 text

Renderer • UI dependent • Оперирует хост-компонентами • Атомарно применяет изменения в конкретной среде

Slide 10

Slide 10 text

О чем поговорим? React Reconciler React → DOM Figma & Figma API React → Figma Итоги

Slide 11

Slide 11 text

import ReactDOM from ‘react-dom’; . . . ReactDOM.render(, root);

Slide 12

Slide 12 text

import Reconciler from 'react-reconciler'; const hostConfig = {}; const render = (jsx, root) => { const reconciler = Reconciler(hostConfig); const container = reconciler.createContainer(root, false, false); reconciler.updateContainer(jsx, container); };

Slide 13

Slide 13 text

import Reconciler from 'react-reconciler'; const hostConfig = {}; const render = (jsx, root) => { const reconciler = Reconciler(hostConfig); const container = reconciler.createContainer(root, false, false); reconciler.updateContainer(jsx, container); };

Slide 14

Slide 14 text

import Reconciler from 'react-reconciler'; const hostConfig = {}; const render = (jsx, root) => { const reconciler = Reconciler(hostConfig); const container = reconciler.createContainer(root, false, false); reconciler.updateContainer(jsx, container); };

Slide 15

Slide 15 text

import Reconciler from 'react-reconciler'; const hostConfig = {}; const render = (jsx, root) => { const reconciler = Reconciler(hostConfig); const container = reconciler.createContainer(root, false, false); reconciler.updateContainer(jsx, container); };

Slide 16

Slide 16 text

import Reconciler from 'react-reconciler'; const hostConfig = {}; const render = (jsx, root) => { const reconciler = Reconciler(hostConfig); const container = reconciler.createContainer(root, false, false); reconciler.updateContainer(jsx, container); };

Slide 17

Slide 17 text

Режимы работы

Slide 18

Slide 18 text

Режимы работы supportsMutation: true Мутирует существующие ноды: • appendChild, insertBefore, removeChild • commitUpdate Например: React DOM, React Figma, …

Slide 19

Slide 19 text

Режимы работы supportsPersistence: true Клонирует и заменяет ноды: • replaceContainerChildren, createContainerChildSet • сloneInstance Например: React Native, canvas, console, …

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

Live code • Отрисовываем React в DOM • Компоненты •
,

, • Атрибуты • className, onClick, src

Slide 22

Slide 22 text

Первоначальная отрисовка

Slide 23

Slide 23 text

const InitialRenderExample = () => (

Hello!

);

Slide 24

Slide 24 text

const InitialRenderExample = () => (

Hello!

);

Slide 25

Slide 25 text

const InitialRenderExample = () => (

Hello!

);

Slide 26

Slide 26 text

1. getRootHostContext

Slide 27

Slide 27 text

Передает первоначальный контекст между вызовами методов getRootHostContext(rootContainerInstance: Container): HostContext

Slide 28

Slide 28 text

1. getRootHostContext 2. getChildHostContext

Slide 29

Slide 29 text

Передает контекст от родителя к детям getChildHostContext(parentContext: HostContext, type: string, …): HostContext

Slide 30

Slide 30 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent

Slide 31

Slide 31 text

Нужно ли обрабатывать текст как отдельные ноды shouldSetTextContent(type: string, props: Props): boolean

Slide 32

Slide 32 text

shouldSetTextContent setTextContent: false const paragraph = document.createElement('p'); const helloText = document.createTextNode('Hello!'); paragraph.appendChild(helloText);

Slide 33

Slide 33 text

shouldSetTextContent setTextContent: true const textarea = document.createElement('textarea'); textarea.value = "Hello!";

Slide 34

Slide 34 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. getChildHostContext 5. shouldSetTextContent

Slide 35

Slide 35 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. getChildHostContext 5. shouldSetTextContent 6. createInstance

Slide 36

Slide 36 text

Создает представление хост-компонента в среде createInstance(type: string, props: Props, …): Instance

Slide 37

Slide 37 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. getChildHostContext 5. shouldSetTextContent 6. createInstance 7. finalizeInitialChildren

Slide 38

Slide 38 text

Совершает дополнительные действия после создания узла finalizeInitialChildren(parent: Instance, type: string, props: Props): boolean

Slide 39

Slide 39 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. getChildHostContext 5. shouldSetTextContent 6. createInstance 7. finalizeInitialChildren 8. getChildHostContext 9. shouldSetTextContent

Slide 40

Slide 40 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. getChildHostContext 5. shouldSetTextContent 6. createInstance 7. finalizeInitialChildren 8. getChildHostContext 9. shouldSetTextContent 10. createTextInstance

Slide 41

Slide 41 text

Создает представление текстового листа createTextInstance(text: string, …): TextInstance

Slide 42

Slide 42 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. getChildHostContext 5. shouldSetTextContent 6. createInstance 7. finalizeInitialChildren 8. getChildHostContext 9. shouldSetTextContent 11. createInstance 10. createTextInstance

Slide 43

Slide 43 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. getChildHostContext 5. shouldSetTextContent 6. createInstance 7. finalizeInitialChildren 8. getChildHostContext 9. shouldSetTextContent 11. createInstance 12. appendInitialChild 10. createTextInstance

Slide 44

Slide 44 text

Добавляет вершину родителю при первоначальной отрисовке appendInitialChild( parent: Instance, child: Instance | TextInstance ): void

Slide 45

Slide 45 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. getChildHostContext 5. shouldSetTextContent 6. createInstance 7. finalizeInitialChildren 8. getChildHostContext 9. shouldSetTextContent 11. createInstance 12. appendInitialChild 10. createTextInstance 13. finalizeInitialChildren

Slide 46

Slide 46 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. getChildHostContext 5. shouldSetTextContent 6. createInstance 7. finalizeInitialChildren 8. getChildHostContext 9. shouldSetTextContent 11. createInstance 12. appendInitialChild 10. createTextInstance 13. finalizeInitialChildren 14. createInstance 15, 16. appendInitialChild 17. finalizeInitialChildren

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. getChildHostContext 5. shouldSetTextContent 6. createInstance 7. finalizeInitialChildren 8. getChildHostContext 9. shouldSetTextContent 11. createInstance 12. appendInitialChild 10. createTextInstance 13. finalizeInitialChildren 14. createInstance 15, 16. appendInitialChild 17. finalizeInitialChildren 18. prepareForCommit

Slide 50

Slide 50 text

Осуществляет подготовку к внесению изменений prepareForCommit(containerInfo: Container): void

Slide 51

Slide 51 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. getChildHostContext 5. shouldSetTextContent 6. createInstance 7. finalizeInitialChildren 8. getChildHostContext 9. shouldSetTextContent 11. createInstance 12. appendInitialChild 10. createTextInstance 13. finalizeInitialChildren 14. createInstance 15, 16. appendInitialChild 17. finalizeInitialChildren 18. prepareForCommit 19. appendChildToContainer

Slide 52

Slide 52 text

Добавляет ребенка в представление appendChildToContainer( container: Container, child: Instance | TextInstance ): void

Slide 53

Slide 53 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. getChildHostContext 5. shouldSetTextContent 6. createInstance 7. finalizeInitialChildren 8. getChildHostContext 9. shouldSetTextContent 11. createInstance 12. appendInitialChild 10. createTextInstance 13. finalizeInitialChildren 14. createInstance 15, 16. appendInitialChild 17. finalizeInitialChildren 18. prepareForCommit 19. appendChildToContainer 20. resetAfterCommit

Slide 54

Slide 54 text

Осуществляет дополнительные действия после внесения изменений resetAfterCommit(containerInfo: Container): void

Slide 55

Slide 55 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. getChildHostContext 5. shouldSetTextContent 6. createInstance 7. finalizeInitialChildren 8. getChildHostContext 9. shouldSetTextContent 11. createInstance 12. appendInitialChild 10. createTextInstance 13. finalizeInitialChildren 14. createInstance 15, 16. appendInitialChild 17. finalizeInitialChildren 18. prepareForCommit 19. appendChildToContainer 20. resetAfterCommit 21. commitMount 22. commitMount 23. commitMount

Slide 56

Slide 56 text

Дополнительная обработка узлов после их отрисовки commitMount(instance: Container, type: string, …): void

Slide 57

Slide 57 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. getChildHostContext 5. shouldSetTextContent 6. createInstance 7. finalizeInitialChildren 8. getChildHostContext 9. shouldSetTextContent 11. createInstance 12. appendInitialChild 10. createTextInstance 13. finalizeInitialChildren 14. createInstance 15, 16. appendInitialChild 17. finalizeInitialChildren 18. prepareForCommit 19. appendChildToContainer 20. resetAfterCommit 21. commitMount 22. commitMount 23. commitMount

Slide 58

Slide 58 text

изменение пропсов Отрисовка изменений

Slide 59

Slide 59 text

No content

Slide 60

Slide 60 text

1. getRootHostContext 2. getChildHostContext 3. getChildHostContext 4. shouldSetTextContent

Slide 61

Slide 61 text

1. getRootHostContext 2. getChildHostContext 3. getChildHostContext 4. shouldSetTextContent 5. prepareUpdate

Slide 62

Slide 62 text

Проверяет есть ли изменения и находит их prepareUpdate( instance: Instance, type: string, oldProps: Props, newProps: Props, …, ): null | UpdatePayload;

Slide 63

Slide 63 text

1. getRootHostContext 2. getChildHostContext 3. getChildHostContext 4. shouldSetTextContent 5. prepareUpdate 6. prepareForCommit

Slide 64

Slide 64 text

1. getRootHostContext 2. getChildHostContext 3. getChildHostContext 4. shouldSetTextContent 5. prepareUpdate 6. prepareForCommit 7. commitUpdate

Slide 65

Slide 65 text

Применяет изменения к элементу commitUpdate(instance: Instance, updatePayload: UpdatePayload, type: string, … ): void;

Slide 66

Slide 66 text

1. getRootHostContext 2. getChildHostContext 3. getChildHostContext 4. shouldSetTextContent 5. prepareUpdate 6. prepareForCommit 7. commitUpdate 8. resetAfterCommit

Slide 67

Slide 67 text

1. getRootHostContext 2. getChildHostContext 3. getChildHostContext 4. shouldSetTextContent 5. prepareUpdate 6. prepareForCommit 7. commitUpdate 8. resetAfterCommit

Slide 68

Slide 68 text

вставка узлов Отрисовка изменений

Slide 69

Slide 69 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. getChildHostContext 5. shouldSetTextContent 7. getChildHostContext 8. shouldSetTextContent 6. prepareUpdate 9. createInstance 10. finalizeInitialChildren 11. prepareUpdate 13. appendChild 12. prepareForCommit 14. resetAfterCommit

Slide 70

Slide 70 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. getChildHostContext 5. shouldSetTextContent 7. getChildHostContext 8. shouldSetTextContent 6. prepareUpdate 9. createInstance 10. finalizeInitialChildren 11. prepareUpdate 13. appendChild 12. prepareForCommit 14. resetAfterCommit

Slide 71

Slide 71 text

Добавляет ребенка в конец списка детей appendChild( parentInstance: Instance, child: Instance | TextInstance ): void

Slide 72

Slide 72 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 11. prepareUpdate 13. insertBefore 12. prepareForCommit 14. resetAfterCommit 4. getChildHostContext 5. shouldSetTextContent 8. getChildHostContext 9. shouldSetTextContent 6. createInstance 10. prepareUpdate 7. finalizeInitialChildren

Slide 73

Slide 73 text

Добавляет ребенка после определенного элемента insertBefore( parentInstance: Instance, child: Instance | TextInstance, beforeChild: Instance | TextInstance ): void

Slide 74

Slide 74 text

Добавляет ребенка после определенного элемента в контейнере insertInContainerBefore( container: Container, child: Instance | TextInstance, beforeChild: Instance | TextInstance ): void

Slide 75

Slide 75 text

удаление узла Отрисовка изменений

Slide 76

Slide 76 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. getChildHostContext 5. shouldSetTextContent 6. prepareUpdate 7. prepareUpdate 8. prepareForCommit 10. resetAfterCommit 9. removeChild

Slide 77

Slide 77 text

Удаляет поддерево removeChild( parentInstance: Instance, child: Instance | TextInstance ): void

Slide 78

Slide 78 text

Удаляет поддерево из контейнера removeChildFromContainer( container: Container, child: Instance | TextInstance ): void

Slide 79

Slide 79 text

текстовые листья Отрисовка изменений

Slide 80

Slide 80 text

1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. prepareUpdate 5. prepareForCommit 6. commitTextUpdate 7. resetAfterCommit

Slide 81

Slide 81 text

Вносит изменения в текстовый лист commitTextUpdate( textInstance: TextInstance, oldText: string, newText: string ): void

Slide 82

Slide 82 text

Что осталось? • Поддержка гидрации • Работа в режиме persistence • Поддержка тестовых селекторов https://github.com/facebook/react/tree/master/packages/react-reconciler

Slide 83

Slide 83 text

О чем поговорим? React Reconciler React → DOM Figma & Figma API React → Figma Итоги

Slide 84

Slide 84 text

No content

Slide 85

Slide 85 text

Figma Plugin API

Slide 86

Slide 86 text

No content

Slide 87

Slide 87 text

Figma API demo https://www.figma.com/plugin-docs/intro/

Slide 88

Slide 88 text

Live code • Отрисовываем React в Figma • Компоненты • , , • Атрибуты • x, y, width, height, backgroundColor

Slide 89

Slide 89 text

А можно ли из Figma в React? • github.com/bernaferrari/FigmaToCode • overlay-tech.com • Зар Захаров, Александр Каменяр — Figma to React: доставка дизайна в код

Slide 90

Slide 90 text

А можно универсально? https://holyjs-moscow.ru/2020/msk/talks/5udhzhsrgbzzg3r496hmge/

Slide 91

Slide 91 text

О чем поговорим? React Reconciler React → DOM Figma & Figma API React → Figma Итоги

Slide 92

Slide 92 text

React Native const WelcomeScreen = () => ( Step One Edit App.js to change… … );

Slide 93

Slide 93 text

Ink const Counter = () => { const [i, setI] = useState(0); useEffect(() => { setInterval(() => { setI((prev) => prev + 1); }, 100); }, []); return {i} tests passed ; };

Slide 94

Slide 94 text

React Hardware const App = () => { const [led, setLed] = useState(false); useEffect(() => { setInterval(() => { setLed((prev) => !prev); }, 1000); }, []); return ; }; const PORT = "/dev/tty.usbmodem1411"; ReactHardware.render(, PORT);

Slide 95

Slide 95 text

React Figma const App = () => ( );

Slide 96

Slide 96 text

React PDF const MyDocument = () => ( ~ Created with react-pdf ~ … … );

Slide 97

Slide 97 text

Всегда последние фишки React Определяется только средозависимая часть React DevTools Hot Reloading Дает лучшее понимание React Весело

Slide 98

Slide 98 text

☹ Мало документации ☹ “Use it at your own risk” ☹ Иногда интегрироваться с host-environment сложно

Slide 99

Slide 99 text

bit.ly/react-reconciler-holy LosYear github.com/losyear twitter.com/losyear