Показаны сообщения с ярлыком React. Показать все сообщения
Показаны сообщения с ярлыком React. Показать все сообщения

23 авг. 2024 г.

State of React memoization in 2023

 https://2023.stateofreact.com/en-US/features/


  • 86% used useMemo()
  • 85% used useCallback()
  • 73% used memo()
About 12% of auditory know something about stable links in component props (via useMemo and useCallback) but need to know how to memoize functional components to use those stable links.

29 мар. 2022 г.

React.StrictMode calls your render() and reducer() twice

In a strict mode development build of React renders your components twice. It calls your render() method, functional components, all the hooks two times. The reducer() function from the useReducer() hook is also called twice.

Before the second call, React disables all console output methods. In case your code works in non-strict mode but shows strange results in strict mode, you may want to see console output from the second call. In order to do that you can store the original console.log method at the very beginning of your code:

import { useReducer } from "react";
// other imports...

const log = console.log;

function MyComponent() {
  const [state, dispatch] = useReducer(reducer, undefined, init);
  log("MyComponent", state); // note: log instead of console.log
  return <div>markup...</div>;
}


19 мар. 2020 г.

Профилирование скорости server-side рендеринга (SSR) компонентов на React + TypeScript

Подготовка

Для запуска ts tsx файлов в Node.js устанавливаем пакет ts-node:

npm i ts-node

Чтобы при запуске игнорировать импорт стилей в файле компонента (который может выглядеть примерно так: import './MyComponent.scss';), устанавливаем пакет ignore-styles:

npm i ignore-styles

Создание файла с бенчмарком

Создаём tsx файл, в котором импортируем наш компонент MyComponent, задаём props и вызываем renderToString():

import * as React from 'react';
import { renderToString } from 'react-dom/server';
import { MyComponent } from './MyComponent';

const props = {/* ... */};
console.log(renderToString(<MyComponent {...props} />));

Запускаем его, чтобы убедиться, что всё работает без ошибок, компонент рендерится и в консоль выводится правильная разметка компонента:

NODE_ENV=production node -r ts-node/register -r ignore-styles MyComponent.perf-test.tsx

Если не хватит памяти, надо добавить параметр --max_old_space_size=4096

NODE_ENV=production node --max_old_space_size=4096 -r ts-node/register -r ignore-styles MyComponent.perf-test.tsx

Если памяти всё равно не хватит - надо поставить вместо 4096 число побольше. Запоминаем подобранные параметры.

Убедившись, что всё работает, в файле бенчмарка убираем вывод в консоль и дописываем вызов renderToString() в цикле:

import * as React from 'react';
import { renderToString } from 'react-dom/server';
import { MyComponent } from './MyComponent';

const props = {/* ... */};

for (let i = 0; i < 1000; i++) {
    renderToString(<MyComponent {...props} />);
}

Запуск бенчмарка

Запускаем бенчмарк (в подобранную ранее командную строку добавляется параметр --prof):

NODE_ENV=production node --prof -r ts-node/register -r ignore-styles MyComponent.perf-test.tsx

или

NODE_ENV=production node --prof --max_old_space_size=4096 -r ts-node/register -r ignore-styles MyComponent.perf-test.tsx

Первый запуск после изменения файла будет долгим и даст совсем неправильные результаты, т.к. под капотом компилируется TypeScript, и процесс компиляции тоже попадёт в собранный профиль, что нам не нужно. Поэтому после каждого редактирования запускаем бенчмарк по два раза, второй раз он выполнится быстрее.

После каждого запуска должны создаваться файлы isolate*.log.

Теперь вместо числа 1000 надо подобрать такое, чтобы второй запуск бенчмарка занимал достаточно продолжительное время (десятки секунд): меняем число, запускаем два раза, оцениваем продолжительность второго запуска.

После этого удаляем все накопившиеся файлы isolate*.log, запускаем бенчмарк ещё раз - мы должны получить ровно один файл isolate*.log.

Обработка и анализ собранного профиля

Полученный файл isolate*.log надо обработать, чтобы получить на выходе читабельный профиль выполнения:

node --prof-process isolate-0x104000800-v8.log >isolate-0x104000800-v8.txt

Вместо isolate-0x104000800-v8 надо подставить своё имя файла. Также для обработки лога можно использовать отдельный пакет https://www.npmjs.com/package/tick-processor, часто он лучше обрабатывает лог и не теряет данные, в обличие от встроенного в саму ноду процессора логов:

tick-processor isolate-0x104000800-v8.log >isolate-0x104000800-v8.txt

В текстовом файле мы видим, какие именно методы v8 и нативного C++ кода вызывались и сколько времени заняли. Подробное описание содержимого и методов его анализа - тема, достойная отдельной большой статьи.

6 мая 2017 г.

How to properly define propTypes for React component

Wrong way

// Wrong! propTypes should be either static property or static property getter
class TextWrongES6 extends Component {
    static propTypes() {
        return { children: PropTypes.string };
    }

    static defaultProps() {
        return { children: 'Hello World!' };
    }

    render() {
        return <p>{this.props.children}</p>;
    }
}

Right ways

// The ES5 way
var TextES5Way = React.createClass({
    propTypes: { children: PropTypes.string },

    getDefaultProps: function() {
        return { children: 'Hello World!' };
    },

    render: function() {
        return <p>{this.props.children}</p>;
    }
});

// The ES6 way - ES6 class + class properties
class TextES6Way1 extends Component {
    render() {
        return <p>{this.props.children}</p>;
    }
}
TextES6Way1.propTypes = { children: PropTypes.string };
TextES6Way1.defaultProps = { children: 'Hello World!' };

// The ES6 way - ES6 class + ES5 getters
class TextES6Way2 extends Component {
    static get propTypes() {
        return { children: PropTypes.string };
    }

    static get defaultProps() {
        return { children: 'Hello World!' };
    }

    render() {
        return <p>{this.props.children}</p>;
    }
}

// The ES7 way - static property initializers (experimental feature)
class TextES7Way extends Component {
    static propTypes = { children: PropTypes.string };
    static defaultProps = { children: 'Hello World!' };

    render() {
        return <p>{this.props.children}</p>;
    }
}

// The Stateless Functional Component way
const Text = (props) => <p>{props.children}</p>;
Text.propTypes = { children: PropTypes.string };
Text.defaultProps = { children: 'Hello World!' };

26 нояб. 2014 г.

Upgrade React to 0.12


  1. Rename React.renderComponent to React.render and use React.createFactory:
    was in 0.11:
    React.renderComponent(ReactClass(props), container)
    should be in 0.12:
    React.render(React.createFactory(ReactClass)(props), container)
  2. Use displayName where possible - it will be used in console messages
  3. Use either JSX or React.createFactory to render children components:
    JSX:
    var Child = React.createClass(...);
    render: function() {
        return <Child name={this.props.name} />;
    }

    JS:
    var Child = React.createClass(...);
    var factory = React.createFactory(Child);
    render: function() {
        return factory({name: this.props.name});
    }
  4. Do not use transferPropsTo. Use explicit props object in JS code or spread operator in JSX:
    JS:
    render: function() {
        return childFactory(_.extend({}, this.props,
            {className: 'name ' + this.props.className});
    }

    or:
    render: function() {
        return React.createElement(Child, props);
    }

    JSX:
    render: function() {
        return <Child {...this.props} className={'name ' + this.props.className} />;
    }
  5. Do not use this.props.key in React class - it is removed from props.
    was in 0.11:
    var Child = React.createClass({
        render: function() {
            return <div data-uid={this.props.key} />;
        }
    });
    ...
    var children = items.map(item => <Child key={item.uid} />);

    should be in 0.12:
    var Child = React.createClass({
        render: function() {
            return <div data-uid={this.props.uid} />;
        }
    });
    ...
    var children = items.map(item => <Child key={item.uid} uid={item.uid} />);

5 нояб. 2014 г.

Повторное использование кода в React

В React отсутствует какое-либо наследование компонентов, так что если необходимо реализовать несколько компонентов с похожим функционалом (и одинаковым кодом), и избежать копирования общего кода, то для этого существует только два способа повторного использования кода:
  1. Mixin (docs)
  2. Компонент-обёртка