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

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

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

React — удивительно универсальная технология, прочно вошедшая в нашу жизнь. Применение React уже давно вышло за пределы веба, его используют в огромном множестве задач: от разработки мобильных приложений и до генерации макетов. Интересно ли вам, как такое стало возможно?

В ходе доклада мы разберем, что такое React Reconciler и как с его помощью создаются рендеры, напишем мини-версию привычного React DOM и увидим, как можно связать React с более экзотичными средами на примере отрисовки React-компонентов в Figma.

Доклад окажется полезным практикующим разработчикам и прольет свет на внутреннее устройство архитектуры React и React DOM.

Yaroslav Losev

November 25, 2020
Tweet

More Decks by Yaroslav Losev

Other Decks in Programming

Transcript

  1. Reconciler hostConfig Набор функций, специфичных для среды отрисовки. Например, как

    создать или изменить узел. Модуль react-reconciler с npm. Является общим для всех отрисовщиков
  2. Reconciler • UI agnostic • Находит изменения дерева элементов •

    Передает найденные изменения отрисовщику
  3. 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); };
  4. 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); };
  5. 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); };
  6. 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); };
  7. 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); };
  8. Режимы работы supportsPersistence: true Клонирует и заменяет ноды: • replaceContainerChildren,

    createContainerChildSet • сloneInstance Например: React Native, canvas, console, …
  9. Live code • Отрисовываем React в DOM • Компоненты •

    <div>, <p>, <img> • Атрибуты • className, onClick, src
  10. 1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. getChildHostContext 5. shouldSetTextContent

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

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

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

    6. createInstance 7. finalizeInitialChildren 8. getChildHostContext 9. shouldSetTextContent 11. createInstance 12. appendInitialChild 10. createTextInstance
  14. 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
  15. 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
  16. 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
  17. 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
  18. 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
  19. 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
  20. 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
  21. Проверяет есть ли изменения и находит их prepareUpdate( instance: Instance,

    type: string, oldProps: Props, newProps: Props, …, ): null | UpdatePayload;
  22. 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
  23. 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
  24. 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
  25. 1. getRootHostContext 2. getChildHostContext 3. shouldSetTextContent 4. getChildHostContext 5. shouldSetTextContent

    6. prepareUpdate 7. prepareUpdate 8. prepareForCommit 10. resetAfterCommit 9. removeChild
  26. Что осталось? • Поддержка гидрации • Работа в режиме persistence

    • Поддержка тестовых селекторов https://github.com/facebook/react/tree/master/packages/react-reconciler
  27. Live code • Отрисовываем React в Figma • Компоненты •

    <frame>, <text>, <rectangle> • Атрибуты • x, y, width, height, backgroundColor
  28. А можно ли из Figma в React? • github.com/bernaferrari/FigmaToCode •

    overlay-tech.com • Зар Захаров, Александр Каменяр — Figma to React: доставка дизайна в код
  29. React Native const WelcomeScreen = () => ( <View> <Header

    title="Welcome to React" /> <Text style={header}> Step One </Text> <Text> Edit App.js to change… </Text> … </View> );
  30. Ink const Counter = () => { const [i, setI]

    = useState(0); useEffect(() => { setInterval(() => { setI((prev) => prev + 1); }, 100); }, []); return <Color green> {i} tests passed </Color>; };
  31. React Hardware const App = () => { const [led,

    setLed] = useState(false); useEffect(() => { setInterval(() => { setLed((prev) => !prev); }, 1000); }, []); return <Led pin={13} value={led ? 255 : 0} />; }; const PORT = "/dev/tty.usbmodem1411"; ReactHardware.render(<App />, PORT);
  32. React Figma const App = () => ( <Frame name="Awesome

    frame"> <Rectangle name="More awesome rectangle" width={200} height={100} backgroundColor="#dd55aa" /> </Frame> );
  33. React PDF const MyDocument = () => ( <Document> <Page

    style={styles.body}> <Text style={styles.header} fixed> ~ Created with react-pdf ~ </Text> … <Image style={styles.image} src="/images/quijote1.jpg" /> … </Page> </Document> );
  34. ☹ Мало документации ☹ “Use it at your own risk”

    ☹ Иногда интегрироваться с host-environment сложно