React 16.6.0 Goodies

React 16.6.0 was released October 2018 and with it came goodies that spice up the way we can develop with React. We’re going to cover what I consider the best of those new goodies with examples of how we can put them to use in our work.

React.memo() avoids unnecessary re-rendering

There are situations where a component re-renders, even if neither its state nor its props changed. That adds up and can be an expensive operation.

Here’s an example of a counter to show what we’re talking about:

See the Pen
React counter w/o React.memo()
by CSS-Tricks (@css-tricks)
on CodePen.

We have a child component that receives a specific value as props that do not change.

const Child = props => { console.log("rendered"); return <React.Fragment>{props.name}</React.Fragment>;
}

The child’s value is determined by the state of the App component. It’s state doesn’t change. It’s props remain the same.

class App extends React.Component { state = { count: 1, name: "Jioke" }; handleClick = () => { this.setState({ count: this.state.count + 1 }); }; render() { return ( <React.Fragment> <Child name={this.state.name} /> <div>{this.state.count}</div> <button onClick={this.handleClick}>+</button> </React.Fragment> ); }
}

Yet, each button click results in two things happening: the value of count is incremented and the child component is re-rendered. Just watch:

We could resolve this with a class component using the shouldComponentUpdate() lifecycle hook, which would look like this:

class Child extends React.Component { // No re-render, please! shouldComponentUpdate(nextProps, nextState) { return nextProps.name != this.props.name } render() { console.log('rendered') return <React.Fragment>{this.props.name}</React.Fragment> }
}

That’s where React.memo() comes into play. It’s a higher-order component we can wrap around the child and, presto, now the child is shielded from unnecessary additional rendering.

const Child = React.memo(props => { console.log("rendered"); return <React.Fragment>{props.name}</React.Fragment>;
});

See the Pen
React.memo 2
by CSS-Tricks (@css-tricks)
on CodePen.

React.lazy() makes importing files a breeze while Suspense provides a fallback UI

Code splitting is crucial in web development—it enables us to import only the files we, which is not only reduces an application’s initial load, but is a core principle of the React framework.

Well, React now enables code splitting using React.lazy() and suspense right at the component level.

By default, if making use of a component (even if its usage depends on a condition), then we import it into the file where you will be using it. React.lazy() can now handle the importation like this:

const MyCounter = lazy(() => import("./Counter"));

This single line returns a promise that resolves to the imported component. From here, we can use the component as we normally would.

const App = () => ( <div> <MyCounter /> </div>
);

There are cases where we might want to render a fallback UI before the component is ready to render. For example, it might take a moment for an API call to fetch and return data. This is a great opportunity to show a loading state while the user waits. Suspense can do just that.

// Using React.lazy() to import the Counter component
const MyCounter = lazy(() => import("./Counter"));
const App = () => ( <div> // Using Suspense to render a loading state while we wait for the Counter <Suspense fallback={<div>Loading...</div>}> <MyCounter /> </Suspense> </div>
);

Suspense’s fallback prop can accept a React element, so go nuts. It can be used to display whatever fallback UI we want while the component loads.

contextType accesses provider context and passes state without render props

The Context API made it possible to share state among multiple components without having to make use of a third-party library.

Well, React 16.6 makes it possible to declare contextType in a component to access the context from a provider. This saves us from having to make use of render props to pass down context to the consumer.

See the Pen
React contextType
by CSS-Tricks (@css-tricks)
on CodePen.

First, let’s create our context:

const UserContext = React.createContext({}); const UserProvider = UserContext.Provider;
const UserConsumer = UserContext.Consumer;

We’ll make use of the provider in the App component:

class App extends React.Component { state = { input: "", name: 'John Doe' }; handleInputChange = event => { event.preventDefault(); this.setState({ input: event.target.value }); }; handleSubmit = event => { event.preventDefault(); this.setState({ name: this.state.input, input: '' }) }; render() { return ( <div> <UserProvider value={{ state: this.state, actions: { handleSubmit: this.handleSubmit, handleInputChange: this.handleInputChange } }} > <User /> </UserProvider> </div> ); }
}

The provider passes the state and the methods to consumer components that will make use of them via the value prop. To access the context, we’ll make use of this.context instead of making render props like we normally would.

class User extends React.Component { static contextType = UserContext; render() { const { state, actions } = this.context; return ( <div> <div> <h2>Hello, {state.name}!</h2> </div> <div> <div> <input type="text" value={state.input} placeholder="Name" onChange={actions.handleInputChange} /> </div> <div> <button onClick={actions.handleSubmit}>Submit</button> </div> </div> </div> ); }
}

We set static contextType to UserContext which we created earlier. With that, we are able to extract the context which includes the state and methods from this.context. We make use of ES6 destructuring to get the values so we can make use of them in the User component, which is the consumer. This looks so much cleaner and is easier to read compared to doing this with render props.

getDerivedStateFromErrors()

We have error boundary to handle errors, which makes use of componentDidCatch() and that gets fired after the DOM has been updated. It’s well suited for error reporting. But now we have getDerivedStateFromErrors() to render a fallback UI before the render completes if an error is caught. Sort of the same concept as Suspense, but for error states instead of loading states.

See the Pen
React getDerivedStateFromError
by CSS-Tricks (@css-tricks)
on CodePen.

Let’s create our error boundary component to capture the moment something goes awry:

class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } // If hasError is true, then trigger the fallback UI static getDerivedStateFromError(error) { return { hasError: true }; } // The fallback UI render() { if (this.state.hasError) { return ( <h1>Oops, something went wrong :(</h1> ); } return this.props.children; }
}

We make use of getDerivedStateFromError() to spot that an error was caught by the error boundary and then return hasError as true when an error occurs. When this happens, we want to display a message to inform the user that an error has encountered.

class Counter extends React.Component { state = { count: 1 } handleClick = () => { this.setState({ count: this.state.count + 1 }) } // If the count is greater than 5, throw an error render() { if (this.state.count > 5) { throw new Error('Error') } return ( <div> <h2>{this.state.count}</h2> <button onClick={this.handleClick}>+</button> </div> ) }
}

That’s going to trigger an error when the value of count is greater than five. Next, we need to wrap our Counter component as a child of ErrorBoundary component to apply the error conditions to the component:

const App = () => ( <div> // Wrap the component in the ErrorBoundary to attach the error conditions and UI <ErrorBoundary> <Counter /> </ErrorBoundary> </div>
)

We can even limit the error to the specific piece that is broken. So, for example, let’s take a listing of locations. Instead swapping the entire list of locations for the error UI, we can slap it at the specific location where the error happened.

See the Pen
React getDerivedStateFromError 1
by Kingsley Silas Chijioke (@kinsomicrote)
on CodePen.

Pretty nice, right?

React continues to add a bunch of useful features while making it easier to write code with each release and v16.6 is no exception. If you’ve already started using any of the latest goodies that shipped in this release, please let me—I’d be interested in seeing how you’re using them in a real project.

More Information

The post React 16.6.0 Goodies appeared first on CSS-Tricks.

Using React Portals to Render Children Outside the DOM Hierarchy

Say we need to render a child element into a React application. Easy right? That child is mounted to the nearest DOM element and rendered inside of it as a result.

render() { return ( <div> // Child to render inside of the div </div> );
}

But! What if we want to render that child outside of the div somewhere else? That could be tricky because it breaks the convention that a component needs to render as a new element and follow a parent-child hierarchy. The parent wants to go where its child goes.

That’s where React Portals come in. They provide a way to render elements outside the DOM hierarchy so that elements are a little more portable. It may not be a perfect analogy, but Portals are sort of like the pipes in Mario Bros. that transport you from the normal flow of the game and into a different region.

The cool thing about Portals? Even though they trigger their own events that are independent of the child’s parent element, the parent is still listening to those events, which can be useful for passing events across an app.

We’re going to create a Portal together in this post then make it into a re-usable component. Let’s go!

The example we’re building

Here’s a relatively simple example of a Portal in action:

See the Pen React Portal by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Toggling an element’s visibility is nothing new. But, if you look at the code carefully, you’ll notice that the outputted element is controlled by the button even though it is not a direct descendent of it. In fact, if you compare the source code to the rendered output in DevTools, you’ll see the relationship:

So the outputted element’s parent actually listens for the button click event and allows the child to be inserted even though it and the button are separate siblings in the DOM. Let’s break down the steps for creating this toggled Portal element to see how it all works.

Step 1: Create the Portal element

The first line of a React application will tell you that an App element is rendered on the document root using ReactDOM. Like this;

ReactDOM.render(<App />, document.getElementById("root"));

We need to place the App element in an HTML file to execute it:

<div id="App"></div>

Same sort of thing with Portals. First thing to creating a Portal is to create a new div element in the HTML file.

<div id="portal"></div>

This div will serve as our target. We’re using #portal as the ID, but it doesn’t have to be that. Any component that gets rendered inside this target div will maintain React’s context. We need to store the div as the value of a variable so we can make use of the Portal component that we’ll create:

const portalRoot = document.getElementById("portal");

Looks a lot like the method to execute the App element, right?

Step 2: Create a Portal component

Next, let’s set up the Portal as a component:

class Portal extends React.Component { constructor() { super(); // 1: Create a new div that wraps the component this.el = document.createElement("div"); } // 2: Append the element to the DOM when it mounts componentDidMount = () => { portalRoot.appendChild(this.el); }; // 3: Remove the element when it unmounts componentWillUnmount = () => { portalRoot.removeChild(this.el); }; render() { // 4: Render the element's children in a Portal const { children } = this.props; return ReactDOM.createPortal(children, this.el); }
}

Let’s step back and take a look at what is happening here.

We create a new div element in the constructor and set it as a value to this.el. When the Portal component mounts, this.el is appended as a child to that div in the HTML file where we added it. That’s the <div id="portal"></div> line in our case.

The DOM tree will look like this.

<div> // Portal, which is also portalRoot <div> // this.el </div>
</div>

If you’re new to React and are confused by the concept of mounting and unmounting an element, Jake Trent has a good explanation. TL;DR: Mounting is the moment the element is inserted into the DOM.

When the component unmounts we want to remove the child to avoid any memory leakage. We will import this Portal component into another component where it gets used, which is the the div that contains the header and button in our example. In doing so, we’ll pass the children elements of the Portal component along with it. This is why we have this.props.children.

Step 3: Using the Portal

To render the Portal component’s children, we make use of ReactDOM.createPortal(). This is a special ReactDOM method that accepts the children and the element we created. To see how the Portal works, let’s make use of it in our App component.

But, before we do that, let’s cover the basics of how we want the App to function. When the App loads, we want to display a text and a button — we can then toggle the button to either show or hide the Portal component.

class App extends React.Component { // The initial toggle state is false so the Portal element is out of view state = { on: false }; toggle = () => { // Create a new "on" state to mount the Portal component via the button this.setState({ on: !this.state.on }); }; // Now, let's render the components render() { const { on } = this.state; return ( // The div where that uses the Portal component child <div> <header> <h1>Welcome to React</h1> </header> <React.Fragment> // The button that toggles the Portal component state // The Portal parent is listening for the event <button onClick={this.toggle}>Toggle Portal</button> // Mount or unmount the Portal on button click <Portal> { on ? <h1>This is a portal!</h1> : null } </Portal> </React.Fragment> </div> ); }
}

Since we want to toggle the Portal on and off, we need to make use of component state to manage the toggling. That’s basically a method to set a state of on to either true or false on the click event. The portal gets rendered when on is true; else we render nothing.

This is how the DOM looks like when the on state is set to true.

When on is false, the Portal component is not being rendered in the root, so the DOM looks like this.

More use cases

Modals are a perfect candidate for Portals. In fact, the React docs use it as the primary example for how Portals work:

See the Pen Example: Portals by Dan Abramov (@gaearon) on CodePen.

It’s the same concept, where a Portal component is created and a state is used to append the its child elements to the Modal component.

We can even insert data from an outside source into a modal. In this example, the App component lists users fetched from an API using axios.

See the Pen React Portal 3 by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

How about tooltips? David Gilberston has a nice demo:

See the Pen React Portal Tooptip by David Gilbertson (@davidgilbertson) on CodePen.

J Scott Smith shows how Portals can be used to escape positioning:

He has another slick example that demonstrates inserting elements and managing state:

Summary

That’s a wrap! Hopefully this gives you a solid base understanding of Portals as far as what they are, what they do, and how to use them in a React application. The concept may seem trivial, but having the ability to move elements outside of the DOM hierarchy is a handy way to make components a little more extensible and re-usable… all of which points to the core benefits of using React in the first place.

More information

The post Using React Portals to Render Children Outside the DOM Hierarchy appeared first on CSS-Tricks.

Rendering Lists Using React Virtualized

Working with data in React is relatively easy because React is designed to handle data as state. The hassle begins when the amount of data you need to consume becomes massive. For example, say you have to handle a dataset which is between 500-1,000 records. This can result in massive loads and lead performance problems. Well, we’re going to look at how we can make use of virtualized lists in React to seamlessly render a long list of data in your application.

We’re going to use the React Virtualized component to get what we need. It will allow us to take large sets of data, process them on the fly, and render them with little-to-no jank.

The setup

React Virtualized already has a detailed set of instructions to get it up and running, so please check out the repo to get started.

We’re going to want data to work with, so we will set up a function which uses faker to create a large data set.

function createRecord(count) { let records = []; for (let i = 0; i < count; i++) { records.push({ username: faker.internet.userName(), email: faker.internet.email() }); } return records;
}

Next, we will pass it the number of data records we want to create, like so:

const records = createRecord(1000);

Alright, now we have what we need to work on rendering a list of those records!

Creating a virtualized list

Here’s the list we want to create, sans styling. We could make use of the few presentational styles that the library includes by importing the included CSS file, but we’re going to leave that out in this post.

See the Pen React Virtualized 1 by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Go ahead and re-run that demo. Crazy fast, right?

You might wonder what the heck React Virtualized is doing behind the scenes to make that happen. Turns out it’s a bunch of crazy and cool sizing, positioning, transforms and transitions that allow the records to scroll in and out of view. The data is already there and rendered. React Virtualized creates a window frame that allows records to slide in and out of view as the user scrolls through it.

To render a virtualized list in React Virtualized, we make use of its List component, which uses a Grid component internally to render the list.

First, we start by setting up rowRenderer, which is responsible for displaying a single row and sets up an index that assigns an ID to each record.

rowRenderer = ({ index, isScrolling, key, style }) => { return ( <div key={key} style={style}> <div>{this.props.data[index].username}</div> <div>{this.props.data[index].email}</div> </div> ); };

As you can see, this returns a single div node that contains two additional divs: one for the username and another for the email. You know, a common list pattern to display users.

rowRenderer accepts several parameters. Here’s what they are and what each one does:

  • index: The numeric ID of a record.
  • isScrolling: Indicates if the scrolling is occurring in the List component.
  • isVisible: Determines if a row is visible or out of view.
  • key: The records position in the array.
  • parent: Defines whether the list is a parent or a child of another list.
  • style: A style object to position the row.

Now that we know more about the rowRenderer function, let’s make put it to use in the List component:

<List rowCount={this.props.data.length} width={width} height={height} rowHeight={rowHeight} rowRenderer={this.rowRenderer} overscanRowCount={3}
/>

You may have noticed a few new parameters. Here’s what they are:

  • rowCount: This takes the numbers of a row in a list that we pass to calculate the length of our list.
  • width: The width of the list.
  • height: The height of the list.
  • rowHeight: This can be a number or a function that returns a row height given its index.
  • rowRenderer: This is responsible for rendering the row. the list is not supposed to be passed directly, so we pass the rowRenderer function that we created in this tutorial.
  • overscanRowCount: This is used to render additional rows in the direction the user scrolls. It reduces the chances of the user scrolling faster than the virtualized content is rendered.

At the end, your code should look something like this;

const { List } = ReactVirtualized ... const height = 700;
const rowHeight = 40;
const width = 800; class App extends React.Component { rowRenderer = ({ index, isScrolling, key, style }) => { return ( <div key={key} style={style}> <div>{this.props.data[index].username}</div> <div>{this.props.data[index].email}</div> </div> ); }; render() { return ( <div> <h2>Details</h2> <List rowCount={this.props.data.length} width={width} height={height} rowHeight={rowHeight} rowRenderer={this.rowRenderer} overscanRowCount={3} /> </div> ); }
}

Cell measurer

According to the documentation, a cell measurer is a higher-order component that is used to temporarily render a list. It’s not yet visible to the user at this point, but the data is held and ready to display.

Why should you care about this? The popular use case is a situation where the value of your rowHeight is dynamic. React Virtualized can render the height of the row on render then cache that height so it no longer needs to calculate as data scrolls out of view — it’s always the right height, no matter the content it contains!

First, we create our cache, which can be done in our component’s constructor using CellMeasurerCache:

constructor() { super() this.cache = new CellMeasurerCache({ fixedWidth: true, defaultHeight: 100 })
}

We make use of the cache when we set up the List component;

<List rowCount={this.props.data.length} width={rowWidth} height={listHeight} deferredMeasurementCache={this.cache} rowHeight={this.cache.rowHeight} rowRenderer={this.renderRow} overscanRowCount={3}
/>

The value passed to deferredMeasurementCache will be used to temporarily rendering the data, then — as the calculated value for rowHeight comes in — additional rows will flow in like they were always there.

Next, though, we will make use of React Virtualized’s CellMeasurer component inside our rowRenderer function instead of the div we initially set up as a placeholder:

rowRenderer = ({ index, parent, key, style }) => { return ( <CellMeasurer key={key} cache={this.cache} parent={parent} columnIndex={0} rowIndex={index} > <div style={style}> <div>{this.props.data[index].username}</div> <div>{this.props.data[index].email}</div> </div> </CellMeasurer> ); };

Now the data is fetched, cached and ready to display in the virtual window at will!

Virtualized table

Yeah, so the main point of this post is to cover lists, but what if we actually want to render data to a table instead? React Virtualized has you covered on that front, too. In this case, we will make use of Table and Column components that come baked into React Virtualized.

Here’s how we would put those components to use in our primary App component:

class App extends React.Component { render() { return ( <div> <h2>Details</h2> <Table width={500} height={300} headerHeight={20} rowHeight={40} rowCount={this.props.data.length} rowGetter={({ index }) => this.props.data[index]} > <Column label='Username' dataKey='username' width={100} /> <Column width={200} label='Email' dataKey='email' /> </Table> </div> ); }
}

The Table component accepts the following parameters:

  • width: The width of the table.
  • height: The height of the table.
  • headerHeight: The table header height.
  • rowHeight: The height of a row given its index.
  • rowCount: This is the initial number of rows we want in the table. It’s the same as the way we defined the number of records we wanted to start with in the List component example.
  • rowGetter: This returns the data of a specific row by its index.

If you take a look at the Column component, you will notice that we put a dataKey parameter to use. That passes the data for each column we called in the dataKey, which receives a unique identifier for that data. Remember that in the function where we create our random data, we make use of two keys; username and email. This is why we have the dataKey of one column set as username and the other set as email.

In conclusion

Hopefully, this walkthrough gives you a good idea of what React Virtualized is capable of doing, how it can make rendering large data sets into lists and tables super fast, and how to put it to use in a project.

We’ve only scratched the surface here. The library is capable of handling a lot of other use cases, like generating placeholders for the data records on scroll, an infinite loading component to fetch and cache data in real-time, a method for allowing arrow keys to navigate through the data, and a slick grid and masonry layouts that we didn’t even cover here.

That should give you a lot to play around with!

Plus, the package is highly maintained. In fact, you can join the Slack group to keep up with the project, contribute to it, and generally get to connect with other folks.

It’s also worth noting that React Virtualized has it own tag in StackOverflow and that can be a good resource to find questions other people have asked about it, or even post your own questions.

Oh, and if you’ve put React Virtualized to use on a project, we’d love to know it! Share it with us in the comments with some notes on how you approached it or what you learned from it.

The post Rendering Lists Using React Virtualized appeared first on CSS-Tricks.

An Overview of Render Props in React

An Overview of Render Props in React

Using render props in React is a technique for efficiently re-using code. According to the React documentation, “a component with a render prop takes a function that returns a React element and calls it instead of implementing its own render logic.” To understand what that means, let’s take a look at the render props pattern and then apply it to a couple of light examples.

The render props pattern

In working with render props, you pass a render function to a component that, in turn, returns a React element. This render function is defined by another component, and the receiving component shares what is passed through the render function.

This is what this looks like:

class BaseComponent extends Component { render() { return <Fragment>{this.props.render()}</Fragment>; }
}

Imagine, if you will, that our App is a gift box where App itself is the bow on top. If the box is the component we are creating and we open it, we’ll expose the props, states, functions and methods needed to make the component work once it’s called by render().

The render function of a component normally has all the JSX and such that form the DOM for that component. Instead, this component has a render function, this.props.render(), that will display a component that gets passed in via props.

Example: Creating a counter

See the Pen React Render Props by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Let’s make a simple counter example that increases and decreases a value depending on the button that is clicked.

First, we start by creating a component that will be used to wrap the initial state, methods and rendering. Creatively, we’ll call this Wrapper:

class Wrapper extends Component { state = { count: 0 }; // Increase count increment = () => { const { count } = this.state; return this.setState({ count: count + 1 }); }; // Decrease count decrement = () => { const { count } = this.state; return this.setState({ count: count - 1 }); }; render() { const { count } = this.state; return ( <div> {this.props.render({ increment: this.increment, decrement: this.decrement, count: count })} </div> ); }
}

In the Wrapper component, we specify the methods and state what gets exposed to the wrapped component. For this example, we need the increment and decrement methods. We have our default count set as 0. The logic is to either increment or decrement count depending on the method that is triggered, starting with a zero value.

If you take a look at the return() method, you’ll see that we are making use of this.props.render(). It is through this function that we pass methods and state from the Wrapper component so that the component that is being wrapped by it will make use of it.

To use it for our App component, the component will look like this:

class App extends React.Component { render() { return ( <Wrapper render={({ increment, decrement, count }) => ( <div> <div> <h3>Render Props Counter</h3> </div> <div> <p>{count}</p> <button onClick={() => increment()}>Increment</button> <button onClick={() => decrement()}>Decrement</button> </div> </div> )} /> ); }
}

Example: Creating a data list

The gain lies in the reusable power of render props, let’s create a component that can be used to handle a list of data which is obtainable from an API.

See the Pen React Render Props 2 by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

What do we want from the wrapper component this time? We want to pass the source link for the data we want to render to it, then make a GET request to obtain the data. When the data is obtained we then set it as the new state of the component and render it for display.

class Wrapper extends React.Component { state = { isLoading: true, error: null, list: [] }; fetchData() { axios.get(this.props.link) .then((response) => { this.setState({ list: response.data, isLoading: false }); }) .catch(error => this.setState({ error, isLoading: false })); } componentDidMount() { this.setState({ isLoading: true }, this.fetchData); } render() { return this.props.render(this.state); }
}

The data link will be passed as props to the Wrapper component. When we get the response from the server, we update list using what is returned from the server. The request is made to the server after the component mounts.

Here is how the Wrapper gets used:

class App extends React.Component { render() { return ( <Wrapper link="https://jsonplaceholder.typicode.com/users" render={({ list, isLoading, error }) => ( <div> <h2>Random Users</h2> {error ? <p>{error.message}</p> : null} {isLoading ? ( <h2>Loading...</h2> ) : ( <ul>{list.map(user => <li key={user.id}>{user.name}</li>)}</ul> )} </div> )} /> ); }
}

You can see that we pass the link as a prop, then we use ES6 de-structuring to get the state of the Wrapper component which is then rendered. The first time the component loads, we display loading text, which is replaced by the list of items once we get a response and data from the server.

The App component here is a class component since it does not manage state. We can transform it into a functional stateless component.

const App = () => { return ( <Wrapper link="https://jsonplaceholder.typicode.com/users" render={({ list, isLoading, error }) => ( <div> <h2>Random Users</h2> {error ? <p>{error.message}</p> : null} {isLoading ? ( <h2>Loading...</h2> ) : ( <ul>{list.map(user => <li key={user.id}>{user.name}</li>)}</ul> )} </div> )} /> );
}

That’s a wrap!

People often compare render props with higher-order components. If you want to go down that path, I suggest you check out this post as well as this insightful talk on the topic by Michael Jackson.

The post An Overview of Render Props in React appeared first on CSS-Tricks.

Working With Events in React

Most of the behavior in an application revolves around events. User enters a value in the registration form? Event. User hits the submit button? Another event. Events are triggered a number of ways and we build applications to listen for them in order to do something else in response.

You may already be super comfortable working with events based on your existing JavaScript experience. However, React has a distinct way of handling them. Rather than directly targeting DOM events, React wraps them in their own event wrapper. But we’ll get into that.

Let’s go over how to create, add and listen for events in React.

Creating Events

We’ll start by creating a form that has an input and a button. An event will be triggered when a value is entered. The button is used to call a function which will reverse that value.

Here’s how it’ll work:

  • An empty input field allows the user to enter text.
  • An onChange event is triggered when values are entered in the input. This calls a function — handleChange() — that is used to set a new state for the input.
  • When the “Reverse Text” button is clicked, another event is triggered. This calls a function — handleReverse() — to set a new state for reversedText.

Here’s that translated into code:

class App extends React.Component { state = { /* Initial State */ input: "", reversedText: "" }; /* handleChange() function to set a new state for input */ handleChange = event => { const value = event.target.value; this.setState({ input: value }); }; /* handleReverse() function to reverse the input and set that as new state for reversedText */ handleReverse = event => { event.preventDefault(); const text = this.state.input; this.setState({ reversedText: text .split("") .reverse() .join("") }); }; render() { return ( <React.Fragment> { /* handleReverse() is called when the form is submitted */ } <form onSubmit={this.handleReverse}> <div> { /* Render input entered */} <label>Text: {this.state.input}</label> </div> <div> { /* handleChange() is triggered when text is entered */ } <input type="text" value={this.state.input} onChange={this.handleChange} placeholder="Enter a text" /> </div> <div> <button>Reverse Text</button> </div> </form> { /* Render reversed text */} <p>Reversed Text: {this.state.reversedText}</p> </React.Fragment> ); }
}}

See the Pen React Event Pen – form by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Listening to component events

Let’s say you have a component like this;

class IncrementButton extends React.Component{ render() { return ( <React.Fragment> <button>+</button> </React.Fragment> ) }
}

Will including it in your App component like this work?

class App extends React.Component{ state = { count: 0 } handleIncrement = (event) => { this.setState({ count: this.state.count + 1}) } render() { return( <React.Fragment> <h1>{this.state.count}</h1> <IncrementButton onClick={this.handleIncrement} /> </React.Fragment> ) }
}

No, it won’t because you can only listen to events on DOM elements. We touched on this at the beginning of the post, but React components are wrappers for DOM elements. That means we essentially have a layer that we need to pass through to listen for the event.

The way around this is to pass the event handler as a prop to the child component. Then the prop is passed down to the click event as an attribute like so:

class IncrementButton extends React.Component{ render() { return ( <React.Fragment> <button onClick={this.props.increaseButton}>+</button> </React.Fragment> ) }
} class App extends React.Component{ state = { count: 0 } handleIncrement = (event) => { this.setState({ count: this.state.count + 1}) } render() { return( <React.Fragment> <h1>{this.state.count}</h1> <IncrementButton increaseButton={this.handleIncrement} /> </React.Fragment> ) }
}

See the Pen React Event Pen – Component Events by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

You could make use of a stateless functional component instead:

const IncrementButton = (props) => { return ( <React.Fragment> <button onClick={props.increaseButton}>+</button> </React.Fragment> )
}

Adding event listeners

There may be times when you want to make use of certain DOM events that are triggered when the component is mounted. Let’s see this using the resize event — we want to see the width of the window whenever it is resized.

class App extends React.Component{ state = { windowWith: window.innerWidth } handleResize = (event) => { this.setState({ windowWith: window.innerWidth }) } render() { return( <React.Fragment> <h1>Window Width</h1> <h1>{this.state.windowWith}</h1> </React.Fragment> ) }
}

If we create a component and try it out like we have below, then the event will not be triggered. We’ll need to add the event listener (handleResize() in this case) and the event type like we have here:

class App extends React.Component{ state = { windowWith: window.innerWidth } handleResize = (event) => { this.setState({ windowWith: window.innerWidth }) } componentDidMount() { window.addEventListener('resize', this.handleResize) } componentDidUnmount() { window.removeEventListener('resize', this.handleResize) } render() { return( <React.Fragment> <h1>Window Width</h1> <h1>{this.state.windowWith}</h1> </React.Fragment> ) }
}

See the Pen React Event Pen – addEventListener by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Now, the event listener will be added when the component mounts. That means our component is actively listening to the browser window and will display its width when it updates.

In summary

OK, so we covered quite a bit of ground in a very small amount of space. We learned that React does not connect directly to a DOM event, but rather Synthetic Events that are wrappers for DOM events. We dug into the process for creating event listeners so that they attach to Synthetic Events and, from there, made sure that a component will update when those events are triggered.

Additional resources

  • Handling Events – React documentation
  • SyntheticEvent – React documentation, including all event types
  • 5 Essential React Concepts to to Know Before Learning Redux – Chris Nwamba provides a nice overview for event handling in React in the second part of this series

The post Working With Events in React appeared first on CSS-Tricks.

How React Reconciliation Works

React is fast! Some of that speed comes from updating only the parts of the DOM that need it. Less for you to worry about and a speed gain to boot. As long as you understand the workings of setState(), you should be good to go. However, it’s also important to familiarize yourself with how this amazing library updates the DOM of your application. Knowing this will be instrumental in your work as a React developer.

The DOM?

The browser builds the DOM by parsing the code you write, it does this before it renders the page. The DOM represents documents in the page as nodes and objects, providing an interface so that programming languages can plug in and manipulate the DOM. The problem with the DOM is that it is not optimized for dynamic state changes, React has to calculate if it is necessary to update the DOM. It does this by creating a virtual DOM and comparing it with the current DOM. In this context, the virtual DOM will contain the new state of the component.

Let’s build a simple component that adds two numbers. The numbers will be entered in an input field.

See the Pen reconciliation Pen by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

First, we’ll need to set up the initial state for the fields, then update the state when a number is entered. The component will look like this:

class App extends React.Component { state = { result: '', entry1: '', entry2: '' } handleEntry1 = (event) => { this.setState({entry1: event.target.value}) } handleEntry2 = (event) => { this.setState({entry2: event.target.value}) } handleAddition = (event) => { const firstInt = parseInt(this.state.entry1) const secondInt = parseInt(this.state.entry2) this.setState({result: firstInt + secondInt }) } render() { const { entry1, entry2, result } = this.state return( <div> <div> <p>Entry 1: { entry1 }</p> <p>Entry 2: { entry2 }</p> <p>Result: { result }</p> </div> <br /> <div> Entry 1:  <input type='text' onChange={this.handleEntry1} /> </div> <br /> <div> Entry 2:  <input type='text' onChange={this.handleEntry2} /> </div> <div> <button onClick={this.handleAddition} type='submit'>Add</button> </div> </div> ) }
}

On initial render, the DOM tree will look like this;

A screenshot from DevTools that shows the HTML rendering of the app.

When an entry is made in the first input field, React creates a new tree. The new tree which is the virtual DOM will contain the new state for entry1. Then, React compares the virtual DOM with the old DOM and, from the comparison, it figures out the difference between both DOMs and makes an update to only the part that is different. A new tree is created each time the state of App component changes — when a value is entered in either of the inputs field, or when the button is clicked.

Animated gif showing how the markup in DevTools changes when numbers are added to the input field.

Diffing Different Elements

When the state of a component changes so that an element needs to be changed from one type to another, React unmounts the whole tree and builds a new one from scratch. This causes every node in that tree to be destroyed.

Let’s see an example:

class App extends React.Component { state = { change: true } handleChange = (event) => { this.setState({change: !this.state.change}) } render() { const { change } = this.state return( <div> <div> <button onClick={this.handleChange}>Change</button> </div> { change ? <div> This is div cause it's true <h2>This is a h2 element in the div</h2> </div> : <p> This is a p element cause it's false <br /> This is another paragraph in the false paragraph </p> } </div> ) }
}

On initial render, you will see the div and its contents and how clicking the button causes React to destroy the div’s tree with its content and build a tree for the <p> element instead. Same happens if we have the same component in both cases. The component will be destroyed alongside the previous tree it belonged to, and a new instance will be built. See the demo below;

See the Pen reconciliation-2 Pen by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Diffing Lists

React uses keys to keep track of items in a list. The keys help it figure out the position of the item on a list. What happens when a list does not have keys? React will mutate every child of the list even if there are no new changes.

In other words, React changes every item in a list that does not have keys.

Here’s an example:

const firstArr = ['codepen', 'codesandbox']
const secondArr = ['github', 'codepen', 'bitbucket', 'codesanbox'] class App extends React.Component { state = { change: true } handleChange = (event) => { this.setState({change: !this.state.change}) } render() { const { change } = this.state return( <div> <div> <button onClick={this.handleChange}>Change</button> </div> <ul> { change ? firstArr.map((e) => <li>{e}</li>) : secondArr.map((e) => <li>{e}</li>) } </ul> </div> ) }
}

Here, we have two arrays that get rendered depending on the state of the component. React has no way of keep track of the items on the list, so it is bound to change the whole list each time there is a need to re-render. This results in performance issues.

In your console, you will see a warning like this:

Warning: Each child in an array or iterator should have a unique "key" prop.

To fix this, you add a unique key for each item on the list.

const firstArr = ['codepen', 'codesandbox']
const secondArr = ['github', 'codepen', 'bitbucket', 'codesanbox'] class App extends React.Component { state = { change: true } handleChange = (event) => { this.setState({change: !this.state.change}) } render() { const { change } = this.state return( <div> <div> <button onClick={this.handleChange}>Change</button> </div> <ul> { change ? firstArr.map((e, index) => <li key={e.index}>{e}</li>) : secondArr.map((e, index) => <li key={e.index}>{e}</li>) } </ul> </div> ) }
}

See the Pen reconciliation-3 Pen by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Wrapping Up

In summary, here are the two big takeaways for understanding how the concept of reconciliation works in React:

  • React can make your reconciliation process.
  • React doesn’t do a full rerender of your DOM nodes. It only changes what it needs to. The diffing process is so fast that you might not notice it.

The post How React Reconciliation Works appeared first on CSS-Tricks.