React v16.3.0: нові життєві цикли та API контексту.

Кілька днів тому ми написали повідомлення про майбутні зміни наших застарілих методів життєвого циклу, включаючи поступові стратегії міграції. У Реакції 16.3.0 ми додаємо кілька нових методів життєвого циклу, щоб допомогти цій міграції. Ми також представляємо нові API для довго запрошених функцій: офіційний API контексту, API пересилання, а також ергономічний API-інтерфейс.

Прочитайте далі, щоб дізнатися більше про випуск.

Офіційний API-контекст

Протягом багатьох років React пропонував експериментальний API для контексту. Незважаючи на те, що це був потужний інструмент, її використання було затьмарене через невід’ємні проблеми в API, і тому ми завжди мали намір замінити експериментальний API кращим.

Версія 16.3 представляє новий контекстний API, який є більш ефективним і підтримує перевірку статичного типу та глибокі оновлення.

Примітка.
Старий контекстний API продовжуватиме працювати на всіх випусках React 16.x, тому ви матимете час для переміщення.

Ось приклад, який показує, як можна вписати “тему” за допомогою нового контекстного API:

const ThemeContext = React.createContext('light');

class ThemeProvider extends React.Component {
  state = {theme: 'light'};

  render (){
    return (
      <ThemeContext.Provider value={this.state.theme}>
        {this.props.children}
      </ThemeContext.Provider>
    );
  }
}

class ThemedButton extends React.Component {
   render () {
      return (
         <ThemeContext.Consumer>
            {theme => <Button theme = {theme} />}
         </ThemeContext.Consumer>
      );
   }
}

Дізнайтеся більше про новий контекстний API тут.

createRef API

Раніше React пропонував два способи управління refs: застарілою API string ref і API зворотного виклику. Хоча API string ref був більш зручним з двох, він мав кілька недоліків, і тому наша офіційна рекомендація полягала в тому, щоб використовувати замість форми форми зворотного виклику.

Версія 16.3 додає нову опцію для управління рефами, що пропонує зручність рядка без будь-яких недоліків:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);

    this.inputRef = React.createRef();
  }

  render() {
    return <input type="text" ref={this.inputRef} />
  }

  componentDidMount() {
    this.inputRef.current.focus();
  }
}

Примітка:
Функція зворотного виклику продовжуватиме підтримуватися на додаток до нового createRef API.

Вам не потрібно замінювати зворотний виклик у ваших компонентах. Вони дещо гнучкі, тому вони залишаться як розширені можливості.

Дізнайтеся більше про новий createRef API тут.

forwardRef API

Компоненти вищого порядку (або HOCs) є поширеним способом повторного використання коду між компонентами. Розділяючи на прикладі контексту теми згори, ми можемо створити HOC, який вводить поточну “тему” як приклад:

function withTheme(Component) {
  return function ThemedComponent(props) {
    return (
      <ThemeContext.Consumer>
         {theme => <Component {...props} theme={theme} />}
      </ThemeContext.Consumer>
    );
  };
}

Ми можемо використовувати вказане вище HOC для компонування проводів до контексту теми без використання ThemeContext безпосередньо. Наприклад:

class FancyButton extends React.Component {
  buttonRef = React.createRef();

  focus() {
    this.buttonRef.current.focus();
  }

  render() {
    const {label, theme, ...rest} = this.props;
    return (
      <button
        {...rest}
        className={`${theme}-button`}
        ref={this.buttonRef}>
        {label}
      </button>
    );
  }
}

const FancyThemedButton = withTheme(FancyButton);

// We can render FancyThemedButton as if it were a FancyButton
// It will automatically receive the current "theme",
// And the HOC will pass through our other props.
<FancyThemedButton
  label="Click me!"
  onClick={handleClick}
/>

HOCs зазвичай передають реквізити до компонентів, які вони обертають. На жаль, посилання не передаються. Це означає, що ми не можемо прикріпити посилання, FancyButton якщо ми використовуємо FancyThemedButton – так що нам не можна зателефонувати focus().

Новий forwardRef API вирішує цю проблему, надаючи спосіб перехопити ref та переслати його як звичайну підтримку:

function withTheme(Component) {
  // Note the second param "ref" provided by React.forwardRef.
  // We can attach this to Component directly.
  function ThemedComponent(props, ref) {
    return (
      <ThemeContext.Consumer>
        {theme => (
          <Component {...props} ref={ref} theme={theme} />
        )}
      </ThemeContext.Consumer>
    );
  }

  // These next lines are not necessary,
  // But they do give the component a better display name in DevTools,
  // e.g. "ForwardRef(withTheme(MyComponent))"
  const name = Component.displayName || Component.name;
  ThemedComponent.displayName = `withTheme(${name})`;

  // Tell React to pass the "ref" to ThemedComponent.
  return React.forwardRef(ThemedComponent);
}

const fancyButtonRef = React.createRef();

// fancyButtonRef will now point to FancyButton
<FancyThemedButton
  label="Click me!"
  onClick={handleClick}
  ref={fancyButtonRef}
/>;

Зміни компонентного життєвого циклу

API-клас компонентів React-у не мав протягом багатьох років великих змін. Однак, оскільки ми додаємо підтримку для більш просунутих функцій (таких як error boundaries і майбутній async rendering mode ), ми розтягуємо цю модель таким чином, що вона не була спочатку призначена.

Наприклад, за допомогою поточного API, занадто легко заблокувати початкове відтворення з несуттєвою логікою. Частково це пов’язано з тим, що занадто багато способів виконувати певне завдання, і це може бути незрозумілим, що є найкращим. Ми помітили, що перериваюча поведінка обробки помилок часто не враховується і може призвести до витоку пам’яті (щось що також вплине на майбутній режим рендеринга асинхронного типу). Поточний компонент API класів також ускладнює інші зусилля, як наша робота над прототипом компілятора React.

Багато з цих проблем поглиблюються підмножина компонентів (життєвий цикл componentWillMount, componentWillReceiveProps і componentWillUpdate). Це також стає життєвими циклами, які викликають найбільше плутанини в спільноті React. З цих причин ми будемо зневажати ці методи на користь кращих альтернатив.

Ми визнаємо, що ця зміна вплине на багато існуючих компонентів. Через це міграційний шлях буде настільки поступовим, як і можливе, і забезпечить втечу. (У Facebook ми підтримуємо більш ніж 50 000 компонентів React. Ми також залежимо від поетапного циклу випуску!)

Примітка:
Попередження попередження буде включено з майбутнім випуском 16.x, але застарілі життєві цикли будуть продовжувати працювати до версії 17.

Навіть у версії 17, вони все одно зможуть їх використовувати, однак вони будуть згладжуватись з префіксом "UNSAFE_", щоб вказати, що вони можуть викликати проблеми. Ми також підготували автоматичний скрипт для перейменування їх у існуючий код.

Окрім того, що ви втрачаєте небезпечні життєві цикли, ми також додаємо пару нових життєвих сюрпризів:

  • getDerivedStateFromProps додається як більш безпечна альтернатива спадщині componentWillReceiveProps.
  • getSnapshotBeforeUpdate додається для підтримки безпечного читання властивостей, наприклад, DOM, до того, як будуть оновлені.

Дізнайтеся більше про ці зміни життєвого циклу тут.

StrictMode Компонент

StrictMode це інструмент для виявлення потенційних проблем у програмі. Любіть Fragment, StrictMode не відображає видимого інтерфейсу. Він активує додаткові перевірки та попередження для своїх нащадків.

Примітка:
StrictMode чеки виконуються тільки в режимі розробки; вони не впливають на виробництво.

Хоча для суворого режиму неможливо усунути всі проблеми (наприклад, певні типи мутацій), це може допомогти багатьом. Якщо ви бачите попередження в строгому режимі, ці речі, швидше за все, призведуть до помилок для асинхронного візуалізації.

У версії 16.3 StrictMode допомагає:

  • Визначення компонентів із небезпечними життєвими циклами
  • Попередження про використання застарілих API рядків
  • Виявлення несподіваних побічних ефектів

Додаткові функціональні можливості будуть додані в майбутніх версіях React.

Дізнайтеся більше про StrictMode компонент тут.

Переклад статті “React v16.3.0: New lifecycles and context API