Latest news about Bitcoin and all cryptocurrencies. Your daily crypto news habit.
We all are aware that react hooks are ready for prime time and many of us have started using it already. But what if we have an existing project we want to move to react hooks that has class components?
This post will guide you through changing an existing class-based component to a hook-based component. This post is not intended to go into the details of hooks.
This is what the documentation says about hooks.
Hooks let us use state and other React features without writing a class.
Let’s begin with an example application. It is a simple counter application. The code is given below:
const initialData = { count: 0, maxLimit: 10};
class Counter extends React.Component { constructor(props) { super(props); this.state = { count: this.props.initialCount }; } onIncrement = () => { this.setState({ count: this.state.count + 1 }); }; onDecrement = () => { this.setState({ count: this.state.count - 1 }); }; render() { return ( <div> <button onClick={this.onDecrement} disabled={this.state.count === this.props.initialCount} > - </button> <div>{this.state.count}</div> <button onClick={this.onIncrement} disabled={this.state.count === this.props.maxLimit} > + </button> </div> ) }}
class CounterApp extends React.Component { render() { const { initialData } = this.props; return ( <React.Fragment> <h2>Counter Example</h2> <Counter initialCount={initialData.count} maxLimit={initialData.maxLimit} /> </React.Fragment> ) }}
ReactDOM.render( <CounterApp initialData={initialData} />, document.getElementById('root'))
As you can see, I have created a simple counter app. The class components created are:
- CounterApp: This is the main app component
- Counter: The actual counter component
Please note that this code is intended for this post and for explanation purpose only. Please ignore any other improvement areas that you may see. ☺
So, to convert a class component to a functional/hooks component, here are the steps:
Pick the smallest class component first i.e. bottom to top approach would be better.
- Move all of the code that a class component has into the render method and make it work, e.g. event handler functions or any other functions or code.
- Update the code to use object de-structuring for props & states.
- Add a line before the class syntax like shown below.
const Counter = () => {}class Counter extends React.Component { /*...code goes here */}
4. Move everything from the render method to the updated function component code block.
const Counter = () => { //...code inside render methods of class component code goes here}class Counter extends React.Component { //...Rest of the code render() { // This will be blank now }}
5. Move the destructured code of props inside the parenthesis of the functional component. Remove the code from inside the code block.
const Counter = ({ maxLimit, count }) => { /*...rest of the code */}
6. Update the component to use hooks like useState or any other hooks that might be needed. Eg.
const Counter = ({ maxLimit, count }) => { //...Rest of the code const [count, setCount] = React.useState(count) //...Rest of the code}
If you have more that one state property, please change it to use hooks for all of them individually. I am not explaining the syntax for how to write hooks here. Please read official documentation for the same.
7. Finally, update the return statement code block to use newly created props (destructured) or the states using hooks. Any other changes made should be incorporated accordingly. And remove the class component line of code altogether.
Alright, that might seem like a lot. Let’s work on the example that we have.
Counter Component
Move the onIncrement and onDecrement code block inside the render method. Define it as const and update the functions this.onIncrement and this.onDecrement to onIncrement and onDecrement respectively.
Use object de-structuring for props and state inside the render method. In our example, you can do something like this:
const { maxLimit, count } = this.propsconst { count } = this.state
Now, just before the class Counter extends React.Component { line, create a line similar to the following:
const Counter = () => {}
Cut everything from render method and paste it in between the curly brackets of the const Counter = () => {}
Move the de-structured props into parenthesis. Line 2 is commented out and Line 1 has the props now {maxLimit, initialCount}.
const Counter = ({ maxLimit, count }) => { // const { maxLimit, initialCount } = this.props; const { count } = this.state // ....Rest of the code}
Next, we need to change our this.state. We will be using useState hooks here. Update the code at Line 2 as shown below:
const Counter = ({ maxLimit, initialCount }) => { const [count, setCount] = React.useState(initialCount); // ....Rest of the code}
The code that we changed is the syntax of using hooks.
Now is the time to update our function to use setCount we defined using hooks. Change the code this.setState that we have inside onIncrement and onDecrement. The updated code will look something like this:
const Counter = ({ maxLimit, initialCount }) => { // ....Rest of the code const onIncrement = () => { setCount(count + 1); }; const onIncrement = () => { setCount(count - 1); }; // ....Rest of the code}
Now, update the code of return statement accordingly to use the new count state (created using hooks) and de-structured props. AND, remove the class Counter extends React.Component {} code completely.
The final code for theCounter component should look like this:
const Counter = ({ maxLimit, initialCount }) => { const [count, setCount] = React.useState(initialCount); const onIncrement = () => { setCount(count + 1); }; const onDecrement = () => { setCount(count - 1); }; return ( <div> <button onClick={onDecrement} disabled={count === initialCount} > - </button> <div>{count}</div> <button onClick={onIncrement} disabled={count === maxLimit} > + </button> </div> )}
So, you might notice that in the end, there is no this being used and code also looks a lot cleaner.
CounterApp Component
The main CounterApp component doesn't have much in it and so we can convert it to a functional component without much hassle. The final code for CounterApp will look like this:
const CounterApp = ({ initialData: {count, maxLimit} }) => { return ( <> <h2>Counter Example</h2> <Counter initialCount={count} maxLimit={maxLimit} /> </> )}
Wondering what <> and </> is? This is an approach to avoid extra layer of elements that we used to created earlier. So, use this or use React.Fragment as shown at the beginning of the article.
The complete counter app code is given below.
const initialData = { count: 0, maxLimit: 10};// added style to make it look better, in case you want to seeconst counterStyles = { h1: { maxWidth: "185px", boxShadow: "5px 5px 4px #888888" }, container: { display: "flex", alignItems: "center" }, button: { width: "30px", borderRadius: "50%", borderStyle: "none", fontSize: "22px", backgroundColor: "khaki", height: "30px", paddingBottom: "5px", cursor: "pointer" }, countDiv: { minWidth: "80px", padding: "0 15px", textAlign: "center", height: "30px", lineHeight: 2, border: "1px solid", borderRadius: "10px", margin: "0 5px" }}
const Counter = ({ maxLimit, initialCount }) => { // styles... const { container, button, countDiv } = counterStyles; const [count, setCount] = React.useState(initialCount); const onIncrement = () => { setCount(count + 1); }; const onDecrement = () => { setCount(count - 1); }; return ( <div style={container}> <button style={button} onClick={onDecrement} disabled={count === initialCount} > - </button> <div style={countDiv}>{count}</div> <button style={button} onClick={onIncrement} disabled={count === maxLimit} > + </button> </div> );};
const CounterApp = ({ initialData: {count, maxLimit} }) => { return ( <> <h2 style={counterStyles.h1}>Counter App: Hooks</h2> <Counter initialCount={count} maxLimit={maxLimit} /> </> );};
ReactDOM.render( <CounterApp initialData={initialData} />, document.getElementById('root'))
Summary
Through this post, we have learned a couple of tips on how to convert a class-based component to a functional and hook-based component. I hope this will help you to migrate your existing code base.
In case of any questions/concerns, feel free to reach out.
Happy Learning!
Originally published at https://www.elanandkumar.com.
Migrating Class Components to Functional using React Hooks was originally published in Hacker Noon on Medium, where people are continuing the conversation by highlighting and responding to this story.
Disclaimer
The views and opinions expressed in this article are solely those of the authors and do not reflect the views of Bitcoin Insider. Every investment and trading move involves risk - this is especially true for cryptocurrencies given their volatility. We strongly advise our readers to conduct their own research when making a decision.