React v.16.3.0 released

Original author: Brian Vaughn
  • Transfer

A few days ago, we wrote a post about upcoming changes in our lifecycle methods , where we also touched on the strategy of gradual migration (updating). In React 16.3.0, we added several new lifecycle methods to help with this migration. We also provided a new API for the long-awaited innovations: the official context API, ref forwarding API and ergonomic ref API.


Official Context API


For many years, React has been providing an experimental contextual API. Even if it was a powerful “thing”, the use of such an API was at risk, since we all wanted to replace the “experimental” API.


Version 16.3 introduces a new context API, which is effective immediately, and supports both static type checking ( static checking of the type ) as well as deep renovation ( deep updates ).


Старое context API будет работать для всех релизов 16й версии, поэтому у вас есть время мигрировать.

Below is an example that shows how you can "prokinut" design theme ( theme is ), using the new 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>
    );
  }
}

More about the context API here.


createRef API


React provided two ways to control refs : specifying ref with a regular string and calling a callback. Although specifying ref simply as a string was more convenient, it had several disadvantages and therefore we recommended using the callback option.


Version 16.3 adds a new option for managing refs, which offers the convenience of specifying ref as a string without flaws:


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();
  }
}

Callback refs будут поддерживаться и далее в новом createRef API. Не спешите заменять callback refs в ваших компонентах. Они более гибкие, поэтому мы оставим их для будущего продвинутого использования.

More about the createRef API here.


forwardRef API


Higher-order components (or HOCs) are a convenient tool for reusing code between components. If we take the previous example with context as a basis, we can create a HOC in which we’ll “hook” the theme as a property ( props ):


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

We can use the HOC, to bind the components with the properties of themes ( theme is ) out of context ( context The ) without ThemeContext directly. For example:


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);

// Мы можем отрисовать FancyThemedButton, как будто это FancyButton
// Компонент автоматически получит текущую тему (*свойство theme*)
// И HOC прокинет его вниз через props.
<FancyThemedButton
  label="Click me!"
  onClick={handleClick}
/>;

Typically, HOCs throw props into the component that they wrap. Unfortunately, refs do not throw . This means that we cannot attach ref to FancyButton when we use FancyThemedButton. It turns out that focus() it is impossible to call focus() .


The forwardRef API solves this problem by proposing to intercept ref and send it further as a regular property.


function withTheme(Component) {
  // обратите внимание, что "ref" предоставлен нам React.forwardRef.
  function ThemedComponent(props, ref) {
    return (
      <ThemeContext.Consumer>
        {theme => (
          <Component {...props} ref={ref} theme={theme} />
        )}
      </ThemeContext.Consumer>
    );
  }

  // Следующие несколько строк кода необязательны,
  // они нужны чтобы дать компоненту понятное имя в DevTools,
  // например, "ForwardRef(withTheme(MyComponent))"
  const name = Component.displayName || Component.name;
  ThemedComponent.displayName = `withTheme(${name})`;

  //  Просим React прокинуть ref в ThemedComponent.
  return React.forwardRef(ThemedComponent);
}

const fancyButtonRef = React.createRef();

// Сейчас fancyButtonRef указывает на FancyButton
<FancyThemedButton
  label="Click me!"
  onClick={handleClick}
  ref={fancyButtonRef}
/>;

Changes in lifecycle methods


The API for creating components using the class has not changed for several years. However, we added support for new "features" (such as error boundaries or the future async rendering mode ) for which this model was not ready as it should.


For example, with the current API, it is very simple to block the initial rendering of the component ( initial render ) by irrelevant logic. In part, this is due to the fact that there are several options for solving the tasks, and therefore choosing the best is not easy. We noticed that error handling is often neglected and this can lead to memory leaks (which in turn will adversely affect asynchronous rendering mode in the future ). The current class API also complicates our other ideas, for example, work on prototyping the React compiler .


Most of these problems are related to the following lifecycle methods: componentWillMount , componentWillReceiveProps, and ComponentWillUpdate . These methods also add the most confusion to the React community. Therefore, we are going to abandon them in favor of a better alternative.


Of course, we understand that such changes will affect a huge number of existing components. Therefore, migration will be gradual as much as possible. We will also offer ways to retreat (We have 50,000 components on Facebook. We also need a gradual update).


Deprecation (устаревший метод) предупреждение будет включено в будущих 16.x релизах, но поддержка текущих "жизненных циклов" будет работать до версии 17. Так же, в семнадцатой версии вы сможете использовать их с префиксом UNSAFE_. Мы приготовили автоматический скрипт для переименования.

In addition to future deprecated life cycle methods, we have added a couple of new ones:


  • occurs .

  • More about the change in lifecycle here.


    StrictMode component


    StrictMode is a tool for finding potential problems in your application. Like Fragment, StrictMode is not visually rendered. This component activates additional checks and warnings.


    StrictMode работает только в development режиме ( в режиме разработки, не в "проде" )

    Despite the fact that it is impossible to catch all the problem areas (for example, some types of mutations), the StrictMode component will help in many situations. If you see a warning in "strict mode" ( strict mode ), then most likely you will have bugs in asynchronous rendering mode ( the async rendering mode ).


    In version 16.3, StrictMode can:


    • find components using unsafe (old) lifecycle methods
    • warn about using the old ref notation API as a string
    • track unforeseen side effects

    Additional functionality will be added in future React releases.


    More about StrictMode here.