About a year ago, the React team released React 16.0. Today, it has been updated to 16.5. There are a lot of exciting features (Fiber architecture, new periodic functions, new Content API, Fragment, Error Boundary, Portal, etc.) that are worth following up on. In this paper, in order to
React Update LogFor reference, pick a few important updates that you can use at work and learn from them. All sample code in
react-upgrade-examples, it is better to eat with the article ~ 😆


directory

0. Updates of life cycle functions

1. The new Content API

2. React Strict Mode

3. Portal

4. Refs

5. Fragment

6. Other

7. To summarize


Updates to life cycle functions

With React 16.0, React uses a new core architecture, Fiber, which breaks the update into two phases: Render Parse and Commit Parse introduce getDerivedStateFromProps, getSnapshotBeforeUpdate, and componentDidCatch. At the same time, also will componentWillUpdate, componentWillReceiveProps and componentWillUpdate marked as unsafe.

New life cycle function legend

new

  • static getDerivedStateFromProps(nextProps, prevState)
  • getSnapshotBeforeUpdate(prevProps, prevState)
  • componentDidCatch(error, info)

Mark it as unsafe

  • componentWillMount(nextProps, nextState)
  • componentWillReceiveProps(nextProps)
  • componentWillUpdate(nextProps, nextState)

static getDerivedStateFromProps(nextProps, prevState)

GetDerivedStateFromProps (nextProps, prevState) updates the state based on the props passed. One of its major features is that it has no side effects: because it is in the Render Phase, every update will be triggered, so the static method is used in the design of THE API, which has the advantage of simplicity — no instance can be accessed, no DOM object can be accessed through ref, etc., ensuring simplicity and efficiency. It is worth noting that side effects can still be generated by the operations of props. In this case, the operation method of props should be moved to componentDidUpdate to reduce the triggering times.

Ex. :

state = { isLogin: false } static getDerivedStateFromProps(nextProps, prevState) { if(nextProps.isLogin ! == prevState.isLogin){ return { isLogin: nextProps.isLogin } } return null } componentDidUpdate(prevProps, prevState){ if(! prevState.isLogin && prevProps.isLogin) this.handleClose() }Copy the code

But be very careful when using, because it’s not like componentWillReceiveProps, to trigger, only when the parent component to render itself calls setState can be set. The official has provided three checklists. Here are some of them:

  1. If you changepropsAt the same time, there are side effects (such as asynchronous requests for data, animation effects), should be usedcomponentDidUpdate
  2. If you want to basepropsTo compute attributes, you should consider memoization of the results, seememoization
  3. If you want to basepropsChange to reset some state, and you should consider using controlled components

Cooperate with componentDidUpdate periodic function, and getDerivedStateFromProps is to replace componentWillReceiveProps appeared. It will update the state componentWillReceiveProps function division, and action/call props, largely avoided the responsibility is not clear and cause too much rendering, should that affect performance.

getSnapshotBeforeUpdate(prevProps, prevState)

GetSnapshotBeforeUpdate (prevProps, prevState) It gets a snapshot before the component is updated — you can pass the calculated value or information from the DOM to the third parameter of the componentDidUpdate(prevProps, prevState, Snapshot) periodic function, Often used for scroll position. From the official example:

Class ScrollingList extends react.component{constructor(props) {super(props) // Get the dom object this.listref = React.createRef() } getSnapshotBeforeUpdate(prevProps, PrevState) {// If (prevProps. List. length < this.props. List.length) {const list = prevProps this.listRef.current return list.scrollHeight - list.scrollTop } return null } componentDidUpdate(prevProps, prevState, Snapshot) {// If (snapshot! == null) { const list = this.listRef.current list.scrollTop = list.scrollHeight - snapshot } } render() { return <div ref={this.listRef}>{/* ... contents... */}</div> } }Copy the code

componentDidCatch(error, info)

Prior to 16.0, error capture was performed using unstable_handleError, which captured very limited information, or using third-party libraries such as react-error-overlay, which was unoffunoffally supported. In 16.0, the componentDidCatch cycle function was added to allow developers to process Error information independently, such as displaying and reporting errors, etc. Users could create their own Error Boundary to capture errors. Ex. :

·· componentDidCatch(error, info) {// Display fallback UI this.setState({hasError: true}); // You can also log the error to an error reporting service logErrorToMyService(error, info); }...Copy the code

In addition, users can also use third-party error tracking services such as Sentry and Bugsnag to ensure efficient error handling while greatly reducing the cost of error tracking for small and medium-sized projects.

Bugsnag error tracking screenshot

Mark it as unsafecomponentWillMount,componentWillReceiveProps,componentWillUpdate

componentWillMount

ComponentWillMount can be used by developers to get first screen data or transaction subscriptions.

To get data quickly, the developers put the first screen request in componentWillMount. The first rendering actually starts when executing componentWillMount. Placing the first screen request on componentWillMount or not does not solve the problem of the first screen rendering of random step data. The official recommendation is to place the first screen in constructor or componentDidMount.

In addition, the event subscription is often used in componentWillMount, and unsubscribe the corresponding event subscription in componentWillUnmount. React does not guarantee that when componentWillMount is called, the same componentWillUnmount will also be called. On the other hand, in the future, when React turns on asynchronous rendering mode, it is very likely that component rendering will be interrupted by other transactions after · is called, resulting in componentWillUnmount not being called. ComponentDidMount does not have this problem. After componentDidMount is called, componentWillUnmount must be called later, and the component will be cleaned up according to the specific code.

ComponentDidMount = componentWillMount ();

componentWillReceiveProps,componentWillUpdate

ComponentWillReceiveProps is marked as unsafe reasons mentioned above, the main reason is the result of the operation props re – render. Similarly, componentWillUpdate is marked as unsafe for the same reason. In addition, DOM updates can cause re-rendering.

For componentWillReceiveProps upgrade scheme is to use getDerivedStateFromProps and componentDidUpdate instead. For componentWillUpdate upgrade scheme is to use componentDidUpdate instead. If a large number of calculations are involved, you can complete the calculations in getSnapshotBeforeUpdate and then update them once at componentDidUpdate.

The use of frame-level apis to restrict or even restrict developers from writing more maintainable Javascript code minimizes anti-pattern development.

New Context API

Before React 16.3, the Context API was officially deprecated because the old Context API, as an experimental product, broke the fractal structure of React. If a component’s shouldComponentUpdate returns false, then the Context API is impenetrable. The uncertainty it creates leads to its not being recommended. With the React 16.3 release, the new Context API is a first-class API that can easily penetrate components without side effects.

// Context lets us pass a value deep into the component tree // without explicitly threading it through every component.  // Create a context for the current theme (with "light" as the default). const ThemeContext = React.createContext('light') class App extends React.Component { render() { // Use a Provider to pass the current theme to the tree below. // Any component can read it, no matter how deep it is. // In this example, we're passing "dark" as the current value. return ( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> ) } } // A component in the middle doesn't have to // pass the theme down explicitly anymore. function Toolbar(props) { return ( <div> <ThemedButton /> </div> ) } function ThemedButton(props) { // Use a Consumer to  read the current theme context. // React will find the closest theme Provider above and use its value. // In this example, the current theme is "dark". return ( <ThemeContext.Consumer>{theme => <Button {... props} theme={theme} />}</ThemeContext.Consumer> ) }Copy the code

The process is roughly as follows:

  1. throughReact.createContextCreating a Context object
  2. On the parent component, use<ThemeContext.Provider/>To provide the Provider
  3. Where consumption is needed, use<ThemeContext.Consumer/>In the form of function calls{theme => <Button {... props} theme={theme} />}Get the value of the Context object.

The Context API with the story

In terms of state management, the new Context API can completely replace part of the Redux application.

const initialState = { theme: 'dark', color: 'blue', } const GlobalStore = React.createContext() class GlobalStoreProvider extends React.Component { render() { return ( <GlobalStore.Provider value={{ ... initialState }}>{this.props.children}</GlobalStore.Provider> ) } } class App extends React.Component { render() { return  ( <GlobalStoreProvider> <GlobalStore.Consumer> {context => ( <div> <div>{context.theme}</div> <div>{context.color}</div> </div> )} </GlobalStore.Consumer> </GlobalStoreProvider> ) } }Copy the code

The ability to penetrate components brought about by the new Context API is useful in scenarios where global state sharing is required, where state can be managed without entering additional dependencies and the code is clean.

React Strict Mode

React StrictMode detects potential problems in applications during development and reminds developers to solve problems, ensuring application robustness. It can mainly detect four problems:

  • Identify life cycle functions that are flagged as unsafe
  • Warn against deprecated apis
  • Detect some methods that produce side effects
  • Check whether the old Context API is used

React StrictMode is easy to use, just wrap a layer around the components that need to be checked React StrictMode

class App extends React.Component {
  render() {
    return (
      <div>
        <React.StrictMode>
          <ComponentA />
        </React.StrictMode>
      </div>
    )
  }
}
Copy the code

If an error occurs, print a specific error message on the console:

React Strict Mode Console output

Portal

The createPortal method provided by the ReactDOM allows components to be rendered to other DOM nodes. This is useful for large applications or for rendering independent of the application itself. The function signature is reactdom.createPortal (child, container), and the child argument is any renderable React Component, such as Element, sting, fragment, etc. Container is the DOM node to be mounted.

Take a simple Modal example, see the code for Portal Modal:

import React from 'react' import ReactDOM from 'react-dom' const modalRoot = document.querySelector('#modal') export default class Modal extends React.Component { constructor(props) { super(props) this.el = document.createElement('div') } componentDidMount() { modalRoot.appendChild(this.el) } componentWillUnmount() { modalRoot.removeChild(this.el) } handleClose = () => [this.props.onClose && this.props.onClose()] render() { const { visible } = this.props if (! visible) return null return ReactDOM.createPortal( <div> {this.props.children} <span onClick={this.handleClose}>[x]</span> </div>, this.el ) } }Copy the code

After passing children using props, use reactdom. createPortal to render container on other DOM nodes.

Refs

React uses the Virtual DOM to update views, but at some point we need to manipulate the real DOM, where the ref attribute comes in handy.

React.createRef

React 16 uses React. CreateRef to get the Ref object.

Before React 16 ··· componentDidMount() {// The refs object container the myRef const el = this.refs.myref // you can also using ReactDOM.findDOMNode // const el = ReactDOM.findDOMNode(this.refs.myRef) } render() { return <div // React 16+ constructor(props) {super(props) this.myref = React. CreateRef ()} render() {// React 16+ constructor(props) {// React 16+ constructor(props) { Return <div ref={this.myref} />} ···Copy the code

React.forwardRef

Another new feature is Ref forwarding, which is intended to give the parent component access to the child component’s Ref to manipulate its DOM. ForwardRef receives a function with parameters like props and ref. For a simple example, see Refs:

const TextInput = React.forwardRef((props, ref) => ( <input type="text" placeholder="Hello forwardRef" ref={ref} /> )) const inputRef = React.createRef() class App  extends Component { constructor(props) { super(props) this.myRef = React.createRef() } handleSubmit = event => { event.preventDefault() alert('input value is:' + inputRef.current.value) } render() { return ( <form onSubmit={this.handleSubmit}> <TextInput ref={inputRef} /> <button type="submit">Submit</button> </form> ) } }Copy the code

This example uses the React. ForwardRef to pass props and ref to the child component, which can be called directly from the parent component.

Fragment

When add elements to the DOM tree volume, a good practice is to create a document createDocumentFragment, first add elements in bulk to the DocumentFragment, again add DocumentFragment to DOM tree, This reduces the number of DOM operations without creating a new element.

Like DocumentFragment, React also has the concept of Fragment for similar purposes. Before React 16, the react-addons-create-fragment extension was used to create fragments. In React 16, use < react. Fragment>
to create a ‘Fragment’ directly. Such as:

render() {
  return (
    <React.Fragment>
      <ChildA />
      <ChildB />
      <ChildC />
    </React.Fragment>
  )
}
Copy the code

This way, we don’t need to wrap a separate layer of useless elements (as with

wrapping), reducing the level of nesting. In addition, there is a concise way to write:

render() {
  return (
    <>
      <ChildA />
      <ChildB />
      <ChildC />
    </>
  )
}
Copy the code

other

ReactDOMrenderThe React Component function can return the React Component as an array

render(){
  return [
    <ComponentA key='A' />,
    <ComponentB key='B' />,
  ]
}
Copy the code

Remove the built-inreact-with-addons.jsAll plug-ins are separate

React-addons -(CSS -)transition-group,react-addons-create-fragment,react-addons-pure-render-mixin, react-Addons-perf, etc Etc., except for part of the built-in, the rest are all independent of a project, pay attention to the use.

conclusion

The React 16.0 ~ 16.5 upgrades give developers a much purer development process. Changes at the API level, architecture changes, and tool classes are all part of the effort to build more maintainable JavaScript applications. Embrace change and go with the flow.

Due to the limited ability of the author, there are omissions in the article, but also hope that readers are generous to give advice. 😀

The above.

Find me on Github.

Reference:

  1. React Docs
  2. Update on Async Rendering
  3. You Probably Don’t Need Derived State
  4. React V16.3: New lifecycle functions
  5. React 16: A look inside an API-compatible rewrite of our frontend UI library

  6. React Fiber Architecture