React 16 — What can it do for you? — Part 2

React 16 has many exciting new features. All you need to know to decide if you should use it, second part of the series.

Rajat S
Bits and Pieces

--

This is the second part in a two-part series. Click here to read Part 1 of this series.

Defining DOM Attributes

Let’s create a simple App component that returns a single <div> element.

class App extends Component {
render() {
return (
<div>
Hello!
</div>
);
}
}

With React 16, you can provide custom attributes to DOM components. We can add a custom attribute to this <div> and set it to any value.

<div my-attribute="foo">Hello!</div>

While this attribute doesn’t really do anything, it show’s how “open” React 16 is. React 15 on the other hand completely ignores any unknown DOM attributes.

You should still follow camel-casing while naming your attributes. For example, if you add tabindex as an attribute to your div, React will ask you to write it as tabIndex instead.

You can also use the attribute class in React 16, allowing you to simple copy and paste standard HTML from anywhere for experimentation. But I would still advise to use React’s className attribute instead.

There are still a few cases where React will not render custom attributes. React will not render the element if the value provided to its attribute is a boolean, a function or a symbol.

For now, React works well for attributes whose values are string, objects, or numbers.

Finally, if your custom attribute starts with “on”, it will not be passed through as it could create a security hole.

Call setState With Null to Avoid Triggering an Update

We will sometimes want to decide if an update to re-render the app should be triggered. In React 16, calling setState with null will no longer trigger a re-render. This way, we can decide if the state gets updated within our setState method itself!

I have built an app that renders a map of either Paris or Vienna. You can switch the city by clicking on one of the buttons. Once you do that, a new map is loaded and rendered after loading is complete. The application initializes the city name, a state, and a constructor.

The city name is passed to the City component, which is actually rendering the map. This component also has the buttons that help us switch between the two maps. But, the City component does not check for changes. It simply loads the map every time an update is triggered. So if my app is currently displaying the map of Vienna and I click on the button to display the map of Vienna, the app will still re-render.

Of the many ways to solve this. One would be to improve the City component to check for changes, but this might further complicate things for you in the future. Instead, I am going to prevent the new update from triggering a re-render.

First I am going to improve the selectCity method to check if the new value is actually same as the existing one. If they are, then I will simply return null for setState. This will prevent an update from being triggered.

selectCity = evt => {
const newValue = evt.target.value;
this.setState (state => {
if (state.city === newValue) {
return null;
}
return {
city: newValue,
};
});
};

You can find the entire code for this here:

Useful tip: Bit helps your team collaborate on shared components. Each component can be independently developed, tested and used across your apps. Bit handles the entire lifecycle of each shared component so you can focus on building great apps.

Rendering Multiple Elements using Fragments

React 16 supports another cool feature called Framents that gives us a convinient way to return multiple children from a component’s render method.

Just like in part 1, I have created an app that renders a list of superheroes.

I can further extend this list using a Heroes component that returns an array.

function Heroes() {
return [
<li key="1">Aquaman</li>,
<li key="2">The Flash</li>,
<li key="3">Wonder Woman</li>
]
}

Call Heroes as a self-closing tag inside the App component’s render method and you will the list of heroes extend.

We can use Fragment to wrap the elements inside the Heroes component. Make sure to import Fragment from react along side Component.

function Heroes() {
return (
<Fragment>
<li>Aquaman</li>
<li>The Flash</li>
<li>Wonder Woman</li>
</Fragment>
)
}

Running the start command, you will find that all the elements will show up. By inspecting the DOM, you will see that all the elements are rendered inside the same <ul> element.

Creating DOM reference using createRef

React’s ref allow us to modify a child that is outside of the typical React dataflow. React 16 comes with a new ref API that provides us with a convenient set of string refs along with the safety of callback refs.

First, I am going create a new App, that renders a bar chart.

Create a file named App.js and write this code snippet inside it.

Also, create another file named Bar.js with the following code inside it.

Here, the app will only render an empty SVG element. To implement a chart, we will need to add a charting library called D3 as a dependency to the project.

yarn add d3

D3 is a really great tool for implementing charts in the app. It needs access to the DOM element to do so. All we need to do is import the library inside Bar.js and add a className to the svg element. We will select the svg element inside a componentDidMount using d3 Like this:

In the typical React dataflow, props is the only way for a parent to interact with its children. But there are a few cases where we will need to modify a child outside of the typical dataflow. React has therefore provided us with an escape hatch called refs. refs allow us to modify a particular instance of a React component or a DOM element.

To create a ref, we use React.createRef() in the BarChart‘s constructor and assign it to this.chartRef.

constructor(props) {
super(props);
this.chartRef = React.createRef();
}

We can use ref to bind the chartRef to the svg element.

<svg ref={this.chartRef} />;

In order to access the svg element, we will change the d3.select‘s argument from (".chart") to (this.chartRef.current).

With this, we can access the svg element. Can now create the actual chart like this:

Running the start script with NPM or Yarn will give us this chart:

We can also use ref to get instances of React components. To showcase this, I am going to add a highlight function in the BarChart component.

highlight = index => {
const transition = d3
.transition()
.duration(450)
.ease(d3.easeLinear);
d3
.select(this.chartRef.current)
.select(`g:nth-child(${index}) rect`)
.transition(transition)
.style("fill", "orange")
.transition(transition)
.style("fill", "steelblue");
};

Inside the App component, I will create a new ref for the barChart and a function that will highlight the third bar.

barChartRef = React.createRef();hightlightThird = () => {
this.barChartRef.current.highlight (3);
};

I will also restructure the component’s render function like this:

render () {
return (
<div>
<BarChart data={[5,8,14,15,22,34]} ref={this.barChartRef} />
<button onClick={this.hightlightThird}>Highlight</button>
</div>
);
}

Run the start script and you will your work perfectly!

The one thing you need to know about refs is that they cannot be used for functional components. This is because functional components do not have instances.

But you can add refs inside a functional component. Here, I can create a ref for an input and provide a button which when clicked will switch the focus to the input. Make sure to call this component inside the App‘s render function.

function FunctionalComponent() {
let inputRef = React.createRef();

function focus() {
inputRef.current.focus();
}
return (
<div>
<input ref={inputRef} />
<button onClick={focus}>Focus</button>
</div>
);
}

That’s a Wrap!

These are just a few of React 16’s many new powerful features. React 16 has brought us many more features that will help us write great React apps, such as:

  • forwardRef — This function will help us extract a ref and pass it to its descendants.
  • getDerivedStateFromProps — This is a lifecycle method that is set to replace componentWillReceiveProps. It is invoked after a component is instantiated as well as when it receives new props. It should return an object to update state, or null to indicate that the new props do not require any state updates.
  • getSnapshotBeforeUpdate — This is a new lifecycle method that is invoked right before the most recently rendered output is committed and the value returned by it will be passed as a third parameter to componentDidUpdate. It enables the component to capture current values before they are potentially changed.
  • React 16 has also introduced a new Context API. It provides a way to share values like that are considered global between components without having to explicitly pass a prop through every level of the tree. You can read more about it here:

This concludes the Part 2 of 2 of this series. You can read Part 1 here.

--

--