React 16 + news

There is a few beautiful news in React 16+. In this blog we will learn about 11 news.

1. Error handling using componentDidCatch Lifecycle Method

“Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed. Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them”

[Dan Abramov]

You can create an error boundary class component by defining a new lifecycle method

 componentDidCatch(error, errorInfo)

The first method parameter is the actual error thrown. The second parameter is an object with a componentStack property containing the component stack trace information.

You can learn more about this function in: MediumSite

2. Render multiple elements without a wrapping element in a component

In React 16 you can render multiple elements without using root.
For example:

In React 15 you must write:

const App = () => <div>  
 <p key="1">React 15 can't return multiple elements ❤️</p>  
 <p key="2">React 15 can't return multiple elements ❤️</p>   
 <p key="3">React 15 can't return multiple elements ❤️</p> 
</div>

But in React 16 you can write:

const App = () => [
  <p key="1">React 16 can return multiple elements ❤️</p>,
  <p key="2">React 16 can return multiple elements ❤️</p>,
  <p key="3">React 16 can return multiple elements ❤️</p>,
];

To avoid array notation and manually added keys to each of the element, you can

use an Aux helper function that simply returns all its children. Like so…

const Aux = props => props.children;

const App = () =>
  <Aux>
    <p>React 16 can return multiple elements ❤️</p>
    <p>React 16 can return multiple elements ❤️</p>
    <p>React 16 can return multiple elements ❤️</p>
  <Aux>;

React 16.2 introduced another way of returning multiple

elements. React.Fragmentabstracted in JSX way via just an empty tag. No extra components needed, no array notation, no keys. Nice!

const App = () => (
  <React.Fragment>
    <p>React 16 can return multiple elements ❤️</p>
    <p>React 16 can return multiple elements ❤️</p>
    <p>React 16 can return multiple elements ❤️</p>
  </React.Fragment>
);

And you can use empty tags like:

const App = () => (
  <>
    <p>React 16 can return multiple elements ❤️</p>
    <p>React 16 can return multiple elements ❤️</p>
    <p>React 16 can return multiple elements ❤️</p>
  </>
);

3. Render text only component

You can create class that retrun only string without tags.

for example:

const App = () =>  return 'Just string!!';

4. Render elements outside the current react tree using portals

React Components map directly into DOM tree. In some cases when you have elements like modals or loaders you need to find a workaround to bring them outside of the current component. React 16 portal feature allows you to attach parts of the Component tree inside a different DOM element.

for example:

render() {  
    var domNode = document.createElement('div');  
    return ReactDOM.createPortal(  
        {this.props.children},  
        domNode  
       );  
 }

5. React 16 came with a couple changes to attributes of DOM components.

or example: camelCase tebIndex instead tabindex etc…

You can find them in React DOM attributes.

6. Call setState with null to Avoid Triggering an Update in React 16

Sometimes it’s desired to decide within an updater function if an update to re-render should be triggered. Calling .setState with null no longer triggers an update in React 16. This means we can decided if the state gets updated within our .setState method itself!

For example:

this.setState(state => {  
  if(state.city === newValue){  
      return null;  
  }  
  return {  
     city: newValue;  
  }  
});

7. Create a DOM reference using createRef in React 16.3

In React 16.3 you’ll be able to use the new React.createRef() function to make ref creation easier.

// declared in class  
 third = React.createRef();  
  
//in render method  
 <input ref={this.thid}/>  
  
   
//to access this input  
 this.third.current.focus();

8. Forwarding Refs

Ref forwarding is a technique for automatically passing a ref through a component to one of its children. This is typically not necessary for most components in the application. However, it can be useful for some kinds of components, especially in reusable component libraries.

example:

const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref} className="FancyButton">{props.children}</button>
));
 // You can now get a ref directly to the DOM button:const 
 const ref = React.createRef();
 <FancyButton ref={ref}>Click me!</FancyButton>;

This way, components using FancyButton can get a ref to the underlying button DOM node and access it if necessary—just like if they used a DOM button directly.

Here is a step-by-step explanation of what happens in the above example:

  1. We create a Rea by calling React.createRef and assign it to a ref variable.
  2. We pass our ref down to by specifying it as a JSX attribute.
  3. React passes the ref to the (props, ref) => ... function inside forwardRef as a second argument.
  4. We forward this ref argument down to button ref={ref} by specifying it as a JSX attribute.
  5. When the ref is attached, ref.current will point to the button DOM node.

9. Update State Based on Props using the Lifecycle Hook getDerivedStateFromProps in React16.3

Instead of componentWillReceiveProps we need to use a new function, static getDerivedStateFromProps

As componentWillReceiveProps gets removed, we need some means of updating the state based on props change — the community decided to introduce a new — static — method to handle this.

This function is static and it has no access to this. So how are we to call this.setState?The answer is — we don’t. Instead the function should return the updated state data, or null if no update is needed.

for exmple:

  static getDerivedStateFromProps(nextProps, prevState) {
    if (nextProps.userId !== prevState.userId) {  
      return {
        userId: nextProps.userId
      };
    }
    // No state update necessary
    return null;
  }

The returned value behaves similarly to current setState value — you only need to return the part of state that changes, all other values will be preserved.

The function call in the first time of the render call and every time when the props change.

After this function is called the function componentDidUpdate is called

Notice: you must initial the state. You can do it in constructor or as class field.

10. Capture values using the lifecycle hook getSnapshotBeforeUpdate in React 16.3

The new getSnapshotBeforeUpdate lifecycle is called right before mutations are made (e.g. before the DOM is updated). The return value for this lifecycle will be passed as the third parameter to componentDidUpdate. (This lifecycle isn’t often needed, but can be useful in cases like manually preserving scroll position during rerenders.)

Together with componentDidUpdate, this new lifecycle should cover all use cases for the legacy componentWillUpdate.

for example:

componentDidMount() {
  this.wrapperRef.current.scrollTop = this.wrapperRef.current.scrollHeight;
} 

getSnapshotBeforUpdate(prevProps, prevState) { 
  const wrapper = this.wrapperRef.current;  
  return wrapper.scrollTop + wrapper.offsetHeight >= wrapper.scrollHeight; 
}

componentDidMount() {  
  if (snapshots){  
    this.wrapperRef.current.scrollTop = this.wrapperRef.current.scrollHeight;  
  }  
}

11. Pass Data through a Component Tree using Context Providers and Consumers in React 16.3

New context API

The new API is accessible as React.createContext() and creates two components for us:

import  React  from  "react";
const  ThemeContext  =  React.createContext({
   foreground: "#fff",
   background: "#666"
});
export  default  ThemeContext;

calling the factory function will return us an object that has a “Provider” and a “Consumer” in it.

The “Provider” is a special component which aims to provide data to all components in its sub-tree, so one example of usage would be:

class  App  extends  Component  {
 render()  {
  return  (
	<ThemeContext.Provider value={ background:  'black',  color:  'red' }>
		<Toolbar  />
	</ThemeContext.Provider>
  );
 }
}
export  default  App;

Here we select a sub-tree (in this case, the whole tree) to which we want to pass our “theme” context, and set the value we want to pass. The value can of course be dynamic (e.g. based on this.state).

Next step is to use the Consumer:

//Toolbar
<ThemeContext.Consumer>
	{({  context })  =>  {
		return  (
		   <div style={ background: context.background, color: context.color }>
				 welcome!
		   </div>
		);
	}}
<ThemeContext.Consumer>