In this tutorial, we started with an existing React-app with which we can calculate how much range the Tesla has under different circumstances. The range of a battery depends on the speed, the outside temperature, the climate and the wheel size.

In order to learn React hooks more thoroughly I converted this existing React-app from React Class Components to one with just React Functional Components. That is the goal of this tutorial!

tesla car battery application

As a starting point for the tutorial, clone this Github repository.

Then, move to the reactjs-app directory:

Project Structure

The project we are working on has the same structure as the aforementioned image and shows the components that make up this application. The index.js is the entry point of the application. App.js is the entry component of the application. The outer edge of the figure above shows the App.js component.       

Application file structure

Breaking Down the UI 

Almost all React applications consist of a composition of components. This application consists of an entry App.js component with the TeslaBattery as a child component. And the TeslaBattery component contains the following child components:

  • TeslaCar: for rendering the TeslaCar image with wheel animation.

  • TeslaStats: for rendering the maximum battery range per Tesla model. This concerns the models: 60, 60D, 75, 75D, 90D, and P100D.

  • TeslaCounter: for manually controlling the speed and the outside temperature.

  • TeslaClimate: this changes the heating to air conditioning when the outside temperature is more than 20 degrees.

  • TeslaWheels: for manually adjusting the wheel size from 19 inches to 20 inches and vice versa.

These child components of the TeslaBattery are already React Functional Components.

But the TeslaBattery is still a React Class Component. In this tutorial, we are going to convert this component to a React Functional Component with hooks in 8 steps. 

But What Is a Hook?

Hooks are functions that let you “hook into” React state and lifecycle features from functional components. Hooks don’t work inside classes. So our first step is to change the class to a function with hooks.

The components tree of the application is as follows:

Component tree

Steps to Convert the TeslaBattery Component to a Functional Component

First, open the source file TeslaBattery.js in your IDE and follow these steps:

1. Change the Class to a Function

Change

To

2. Remove the Render Method

Remove the render method, but keep everything after,  including the return. Make this the last statement in your function.

From

To

You see that we also removed this.state in the first line. This is because we handle state in a different way (see step 5).

3. Convert All Cethods to Functions

Class methods won’t work inside a function, so let’s convert them all to functions (closures).

From

To

Note: Do this also for all other methods!

4. Remove this.state Throughout the Component

The this.state variable in your function isn’t useful anymore. Remove the references to it throughout your render and functions. In step 6, we use the useState hook for this.

5. Remove References to this

The this variable in your function isn’t useful any more. Remove the references to it throughout your render and functions.

6. Remove the Constructor

Simply removing the constructor is a little tricky, so I’l break it down further.

1. Remove Event Handler Bindings

We don’t need to bind event handlers any more with functional components. So if you were doing this;

You can simply remove these lines (What a gross, overly verbose syntax anyway).

2. useState Hook

Instead of

Use the useState hook

What does calling useState do? It declares a “state variable”. Our variables are called carstats and config, but we could call it anything else, like ‘banana’. This is a way to “preserve” some values between the function calls — useState is a new way to use the exact same capabilities that this.state provides in a class. Normally, variables “disappear” when the function exits but state variables are preserved by React.

What do we pass to useState as an argument? The only argument to the useState() hook is the initial state. Unlike with classes, the state doesn’t have to be an object. We can keep a number or a string if that’s all we need. In our example, we pass an empty array as initial state for our variable carstats. And we pass an object with default values as initial state for our variable config.

What does useState return? It returns a pair of values: the current state and a function that updates it. This is why we write const [carstats, setCarstats] = useState([]). This is similar to this.state.carstats and this.setState() in a class, except you get them in a pair.

So, do not use this.setState() in Functional Component.  this.setState() works only in Class Components to update the state of variablesSee step 7.

Finally import your hook:

7. Replace this.setState

this.setState obviously doesn’t exist any more in our function component. Instead, we need to replace each of our setState calls with the relevant state variable setter.

Replace first the this.setState for carstats:

With the setCarstats – setter

Attention! Call React hooks always at the Top Level of your function.

AND

Replace the this.setState for config:

Note: You see in this example how this.setState accept a callback (() => {this.statsUpdate()) that would run after the state-object (i.e. the config-object) is updated? Well our useState updater function does no such thing. Instead, we have to use the useEffect hook. This is explained in the next section.

Replace this.setState with this setConfig – setter:

Do this also for the following event handlers for setting the state of the config-object: 

  • handleChangeClimate(size).
  • handleChangeWheels(size).

8. Replace Lifecycle Methods With the useEffect Hooks

First import your useEffect hook

Replace ComponentDidMount()

Instead of using the componentDidMount lifecycle method, use the useEffect hook with the dependency array filled: [config] !

Replace

With

The Effect Hook lets you perform side effects in Functional Components. The side effect here is executing the statsUpdate() function.

The dependency array [config] given in parameters lets you fire the side effect only when the config-object in the array is changed. This way, you can easily create lifecycle methods like componentDidMount and componentDidUpdate via the Effect hook.

What does useEffect do? By using this Hook, you tell React that your component needs to do something after render. React will remember the function you passed (we’ll refer to it as our “effect”), and call it later after performing the DOM updates. In this effect, we call the statsUpdate() function, but we could also perform data fetching or call some other imperative API.

Does useEffect run after every render? Yes! By default, it runs both after the first render and after every update. Instead of thinking in terms of “mounting” and “updating”, you might find it easier to think that effects happen “after render”. React guarantees the DOM has been updated by the time it runs the effects.

Motivation of Using Hooks

With Hooks, you can extract stateful logic from a component so it can be tested independently and reused. Hooks allow you to reuse stateful logic without changing your component hierarchy. This makes it easy to share Hooks among many components or with the community.

And Hooks let you split one component into smaller functions based on what pieces are related (such as setting up a subscription or fetching data), rather than forcing a split based on lifecycle methods.

Conclusion

In order to learn this more thoroughly I converted an existing React-app from class components to one with just functional components using just the hooks in this article. The result was dramatically cleaner and easier to read code.

I can’t see any reason why I would not use hooks exclusively in the future. I look forward to creating custom hooks and using some of the more advanced features that hooks have to offer.



Source link

Write A Comment