avatarBalaji Dharma

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

13690

Abstract

class="hljs-name">h2</span>></span>Time Now {date.toLocaleTimeString()}.<span class="hljs-tag"></<span class="hljs-name">h2</span>></span> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span> ); }

<span class="hljs-keyword">const</span> element = <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Timenow</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"World"</span> /></span></span>; <span class="hljs-title class_">ReactDOM</span>.<span class="hljs-title function_">render</span>( element, <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">'root'</span>) );</pre></div><p id="711f"><a href="https://codepen.io/balajidharma/pen/WNZKWNa">Try it on CodePen</a></p><p id="9198"><b>Winner: Functional Component</b></p><p id="bed4">The <code>state</code> initialization is done by using the <code>useState</code> hook. No <code>constructor</code> method is required.</p><h2 id="e371">4. Lifecycle Methods</h2><p id="16f4">In React, each component has several <code>lifecycle</code> methods, this method helps you to run code at particular times in the process. <a href="https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/">Click here</a> to view the React lifecycle diagram.</p><p id="c39c"><b>Class Component with Lifecycle Methods</b></p><p id="2ba2">The below clock class component is a perfect example of implementing lifecycle methods.</p><div id="4c7c"><pre><span class="hljs-keyword">class</span> <span class="hljs-title class_">Clock</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_ inherited__">React.Component</span> { <span class="hljs-title function_">constructor</span>(<span class="hljs-params">props</span>) { <span class="hljs-variable language_">super</span>(props); <span class="hljs-variable language_">this</span>.<span class="hljs-property">state</span> = {<span class="hljs-attr">date</span>: <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>()}; }

<span class="hljs-title function_">componentDidMount</span>(<span class="hljs-params"></span>) { <span class="hljs-variable language_">this</span>.<span class="hljs-property">timerID</span> = <span class="hljs-built_in">setInterval</span>( <span class="hljs-function">() =></span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">tick</span>(), <span class="hljs-number">1000</span> ); }

<span class="hljs-title function_">componentWillUnmount</span>(<span class="hljs-params"></span>) { <span class="hljs-built_in">clearInterval</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">timerID</span>); }

<span class="hljs-title function_">tick</span>(<span class="hljs-params"></span>) { <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">setState</span>({ <span class="hljs-attr">date</span>: <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>() }); }

<span class="hljs-title function_">render</span>(<span class="hljs-params"></span>) { <span class="hljs-keyword">return</span> ( <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">h1</span>></span>Hello, world!<span class="hljs-tag"></<span class="hljs-name">h1</span>></span> <span class="hljs-tag"><<span class="hljs-name">h2</span>></span>It is {this.state.date.toLocaleTimeString()}.<span class="hljs-tag"></<span class="hljs-name">h2</span>></span> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span> ); } }

<span class="hljs-title class_">ReactDOM</span>.<span class="hljs-title function_">render</span>( <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Clock</span> /></span></span>, <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">'root'</span>) );</pre></div><p id="3c4f"><a href="https://codepen.io/gaearon/pen/amqdNA">Try it on CodePen</a></p><p id="4562"><b>Functional Component with Lifecycle Hook Methods</b></p><p id="d8e2">We converted above the <code>clock</code> class component into a functional component using the <a href="https://reactjs.org/docs/hooks-reference.html#useeffect"><code>useEff</code>ect</a> hook.</p><p id="c4d9">The <code>useEffect</code> return method is used to clean up.</p><div id="d498"><pre><span class="hljs-keyword">function</span> <span class="hljs-title function_">Clock</span>(<span class="hljs-params">props</span>) { <span class="hljs-keyword">const</span> [date, setDate] = <span class="hljs-title class_">React</span>.<span class="hljs-title function_">useState</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>());

<span class="hljs-title class_">React</span>.<span class="hljs-title function_">useEffect</span>(<span class="hljs-function">() =></span> { <span class="hljs-keyword">var</span> timerID = <span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =></span> <span class="hljs-title function_">tick</span>(), <span class="hljs-number">1000</span>);

<span class="hljs-keyword">return</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">cleanup</span>(<span class="hljs-params"></span>) {
  <span class="hljs-built_in">clearInterval</span>(timerID);
};

});

<span class="hljs-keyword">function</span> <span class="hljs-title function_">tick</span>(<span class="hljs-params"></span>) { <span class="hljs-title function_">setDate</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>()); }

<span class="hljs-keyword">return</span> ( <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">h1</span>></span>Hello, world!<span class="hljs-tag"></<span class="hljs-name">h1</span>></span> <span class="hljs-tag"><<span class="hljs-name">h2</span>></span>It is {date.toLocaleTimeString()}.<span class="hljs-tag"></<span class="hljs-name">h2</span>></span> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span> ); }

<span class="hljs-title class_">ReactDOM</span>.<span class="hljs-title function_">render</span>( <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Clock</span> /></span></span>, <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">'root'</span>) );</pre></div><p id="1868"><a href="https://codepen.io/gaearon/pen/amqdNA">Try it on CodePen</a></p><p id="9204"><b>Winner: Class Component</b></p><p id="9abe">The functional component <code>useEffect</code> is confusing due to using the same hook for all the lifecycle methods. In the class component, we can directly use the methods <code>componentDidMount</code>, <code>componentWillUnmount</code>, etc.</p><h2 id="851b">5. Accessing Components Children</h2><p id="7829">The special <code>children</code> prop is used to access the component inside content or component like <layout>inside content</layout>.</p><p id="fd36"><b>Class Component</b></p><p id="19ef"><code>this.props.children</code> is used for class components.</p><div id="7327"><pre><span class="hljs-keyword">class</span> <span class="hljs-title class_">Layout</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_ inherited__">React.Component</span> { <span class="hljs-title function_">render</span>(<span class="hljs-params"></span>) { <span class="hljs-keyword">return</span>( <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">h1</span>></span>Hello {this.props.name}!<span class="hljs-tag"></<span class="hljs-name">h1</span>></span> <span class="hljs-tag"><<span class="hljs-name">div</span>></span>{this.props.children}<span class="hljs-tag"></<span class="hljs-name">div</span>></span> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span> ); } }

<span class="hljs-keyword">const</span> element = <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Layout</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"World"</span>></span>This is layout content<span class="hljs-tag"></<span class="hljs-name">Layout</span>></span></span>; <span class="hljs-title class_">ReactDOM</span>.<span class="hljs-title function_">render</span>( element, <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">'root'</span>) );</pre></div><p id="7368"><a href="https://codepen.io/balajidharma/pen/XWexdmj">Try it on CodePen</a></p><p id="6b34"><b>Functional Component</b></p><p id="5ca0">Just <code>props.children</code> is used in functional components to access the children's content.</p><div id="46dd"><pre><span class="hljs-keyword">function</span> <span class="hljs-title function_">Layout</span>(<span class="hljs-params">props</span>) { <span class="hljs-keyword">return</span>( <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">h1</span>></span>Hello {props.name}!<span class="hljs-tag"></<span class="hljs-name">h1</span>></span> <span class="hljs-tag"><<span class="hljs-name">div</span>></span>{props.children}<span class="hljs-tag"></<span class="hljs-name">div</span>></span> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span> ); }

<span class="hljs-keyword">const</span> element = <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Layout</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"World"</span>></span>This is layout content<span class="hljs-tag"></<span class="hljs-name">Layout</span>></span></span>; <span class="hljs-title class_">ReactDOM</span>.<span class="hljs-title function_">render</span>( element, <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">'root'</span>) );</pre></div><p id="c80d"><a href="https://codepen.io/balajidharma/pen/BawqKBv">Try it on CodePen</a></p><p id="48b9"><b>Winner: Class & Functional Component</b></p><p id="dda8">Both use the same <code>props.children</code> to access the component children. In addition, we need to use the <code>this</code> keyword.</p><h2 id="d2d6">6. Higher-Order Components</h2><p id="39e4">A higher-order component (HOC) is an advanced technique in React for reusing component logic. HOC is a pure function, so it only returns a new component.</p><blockquote id="ecfc"><p>Higher-order component is a function that takes a component and returns a new component.</p></blockquote><p id="d33d"><b>HOC with Class Component</b></p><div id="fe72"><pre><span class="hljs-keyword">function</span> <span class="hljs-title function_">classHOC</span>(<span class="hljs-params">WrappedComponent</span>) { <span class="hljs-keyword">return</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">extends</span> <span class="hljs-title class_">React</span>.<span class="hljs-property">Component</span>{ <span class="hljs-title function_">render</span>(<span class="hljs-params"></span>) { <span class="hljs-keyword">return</span> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">WrappedComponent</span> {<span class="hljs-attr">...this.props</span>}/></span></span>; } } }

<span class="hljs-keyword">const</span> <span class="hljs-title function_">Hello</span> = (<span class="hljs-params">{ name }</span>) => <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">h1</span>></span>Hello {name}!<span class="hljs-tag"></<span class="hljs-name">h1</span>></span></span>; <span class="hljs-keyword">const</span> <span class="hljs-title class_">NewComponent</span> = <span class="hljs-title function_">classHOC</span>(<span class="hljs-title class_">Hello</span>);

<span class="hljs-keyword">const</span> element = <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">NewComponent</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"World"</span> /></span></span>; <span class="hljs-title class_">ReactDOM</span>.<span class="hljs-title function_">render</span>( element, <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">'root'</span>) );</pre></div><p id="e6e1"><a href="https://codepen.io/balajidharma/pen/NWaOrNb">Try it on CodePen</a></p><p id="e17d"><b>HOC with Functional Component</b></p><div id="6a1d"><pre><span class="hljs-keyword">function</span> <span class="hljs-title function_">functionalHOC</span>(<span class="hljs-params">WrappedComponent</span>) { <span class="hljs-keyword">return</span> <span class="h

Options

ljs-function">(<span class="hljs-params">props</span>) =></span> { <span class="hljs-keyword">return</span> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">WrappedComponent</span> {<span class="hljs-attr">...props</span>}/></span></span>; } }

<span class="hljs-keyword">const</span> <span class="hljs-title function_">Hello</span> = (<span class="hljs-params">{ name }</span>) => <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">h1</span>></span>Hello {name}!<span class="hljs-tag"></<span class="hljs-name">h1</span>></span></span>; <span class="hljs-keyword">const</span> <span class="hljs-title class_">NewComponent</span> = <span class="hljs-title function_">functionalHOC</span>(<span class="hljs-title class_">Hello</span>);

<span class="hljs-keyword">const</span> element = <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">NewComponent</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"World"</span> /></span></span>; <span class="hljs-title class_">ReactDOM</span>.<span class="hljs-title function_">render</span>( element, <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">'root'</span>) );</pre></div><p id="3734"><a href="https://codepen.io/balajidharma/pen/dyVgXKy">Try it on CodePen</a></p><p id="c1d2"><b>Winner: Functional Component</b></p><p id="a16f">To create HOC, we should use the JavaScript function (classHOC, functionalHOC). <a href="https://reactjs.org/docs/higher-order-components.html#dont-use-hocs-inside-the-render-method">Don’t Use HOCs inside the render method</a>. Inside the function, we can use a class or functional components.</p><h2 id="e8ae">7. Error Boundaries</h2><p id="51db"><a href="https://reactjs.org/docs/error-boundaries.html">Error boundaries</a> are React components used to handle JavaScript errors in React components. So we can catch JavaScript runtime errors in our components and display a fallback UI.</p><blockquote id="e5f9"><p>Error boundaries are React components that <b>catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI</b> instead of the component tree that crashed.</p></blockquote><p id="484c">If <a href="https://reactjs.org/docs/react-component.html#static-getderivedstatefromerror"><code>static getDerivedStateFromErro</code>r()</a> or <a href="https://reactjs.org/docs/react-component.html#componentdidcatch"><code>componentDidCatc</code>h()</a> lifecycle methods used means that the class component becomes an error boundary. Use <code>static getDerivedStateFromError()</code> to render a fallback UI after an error has been thrown. Use <code>componentDidCatch()</code> to log error information.</p><p id="35ad">Error boundaries work as a JavaScript <code>catch {}</code> block, but for components.</p><p id="36c9">Simple example with error boundaries</p><div id="5fff"><pre><span class="hljs-keyword">class</span> <span class="hljs-title class_">ErrorCounter</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_ inherited__">React.Component</span> { <span class="hljs-title function_">constructor</span>(<span class="hljs-params">props</span>) { <span class="hljs-variable language_">super</span>(props); <span class="hljs-variable language_">this</span>.<span class="hljs-property">state</span> = {<span class="hljs-attr">error</span>: <span class="hljs-literal">null</span>, <span class="hljs-attr">errorInfo</span>: <span class="hljs-literal">null</span>}; }

<span class="hljs-title function_">componentDidCatch</span>(<span class="hljs-params">error, errorInfo</span>) { <span class="hljs-comment">// Catch errors in any components below and re-render with error message</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">setState</span>({ <span class="hljs-attr">error</span>: error, <span class="hljs-attr">errorInfo</span>: errorInfo }) <span class="hljs-comment">// You can also log error messages to an error reporting service here</span> }

<span class="hljs-title function_">refreshPage</span>(<span class="hljs-params"></span>) { history.<span class="hljs-title function_">go</span>(-<span class="hljs-number">1</span>) }

<span class="hljs-title function_">render</span>(<span class="hljs-params"></span>) { <span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span>.<span class="hljs-property">state</span>.<span class="hljs-property">errorInfo</span>) { <span class="hljs-comment">// Error path</span> <span class="hljs-keyword">return</span> ( <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">h2</span>></span>Something went wrong.<span class="hljs-tag"></<span class="hljs-name">h2</span>></span> <span class="hljs-tag"><<span class="hljs-name">details</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">whiteSpace:</span> '<span class="hljs-attr">pre-wrap</span>' }}></span> {this.state.error && this.state.error.toString()} <span class="hljs-tag"><<span class="hljs-name">br</span> /></span> {this.state.errorInfo.componentStack} <span class="hljs-tag"></<span class="hljs-name">details</span>></span> <span class="hljs-tag"><<span class="hljs-name">hr</span> /></span> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{this.refreshPage}</span>></span> Refresh Page <span class="hljs-tag"></<span class="hljs-name">button</span>></span> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span> ); } <span class="hljs-comment">// Normally, just render children</span> <span class="hljs-keyword">return</span> <span class="hljs-variable language_">this</span>.<span class="hljs-property">props</span>.<span class="hljs-property">children</span>; } }; <span class="hljs-keyword">class</span> <span class="hljs-title class_">Counter</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_ inherited__">React.Component</span> { <span class="hljs-title function_">constructor</span>(<span class="hljs-params">props</span>) { <span class="hljs-variable language_">super</span>(props); <span class="hljs-variable language_">this</span>.<span class="hljs-property">state</span> = { <span class="hljs-attr">counter</span>: <span class="hljs-number">0</span> }; <span class="hljs-variable language_">this</span>.<span class="hljs-property">handleClick</span> = <span class="hljs-variable language_">this</span>.<span class="hljs-property">handleClick</span>.<span class="hljs-title function_">bind</span>(<span class="hljs-variable language_">this</span>); }

<span class="hljs-title function_">handleClick</span>(<span class="hljs-params"></span>) { <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">setState</span>(<span class="hljs-function">(<span class="hljs-params">{counter}</span>) =></span> ({ <span class="hljs-attr">counter</span>: counter + <span class="hljs-number">1</span> })); }

<span class="hljs-title function_">render</span>(<span class="hljs-params"></span>) { <span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span>.<span class="hljs-property">state</span>.<span class="hljs-property">counter</span> === <span class="hljs-number">3</span>) { <span class="hljs-comment">// Simulate a JS error</span> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Error</span>(<span class="hljs-string">'I crashed!'</span>); } <span class="hljs-keyword">return</span>( <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">h1</span>></span>{this.state.counter}<span class="hljs-tag"></<span class="hljs-name">h1</span>></span> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{this.handleClick}</span>></span>+<span class="hljs-tag"></<span class="hljs-name">button</span>></span> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span> ); } }

<span class="hljs-title class_">ReactDOM</span>.<span class="hljs-title function_">render</span>( <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">ErrorCounter</span>></span> <span class="hljs-tag"><<span class="hljs-name">Counter</span> /></span> <span class="hljs-tag"></<span class="hljs-name">ErrorCounter</span>></span></span>, <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">'root'</span>) );</pre></div><p id="761a"><a href="https://codepen.io/balajidharma/pen/eYGQxJY">Try it on CodePen</a></p><p id="4e36"><b>Winner: Class Component</b></p><p id="044a">Currently, only class components can be Error Boundaries.</p><h1 id="0015">Conclusion: Which is better?</h1><p id="40aa">Nowadays most apps use functional components due to their simplicity, ease of use, and understanding. Also, functional components have become very famous after hooks were introduced in React <a href="https://reactjs.org/docs/hooks-intro.html">v16.8</a>.</p><p id="70c4">Lifecycle methods in functional components are easy to use thanks to hooks.</p><p id="6711">Class components are hard to understand for new people who don’t have a background in ES6 JavaScript where classes were introduced.</p><p id="3df8">Unlike other programming languages such as Java, PHP, and C#, JavaScript classes are syntactic sugar over the prototypal inheritance. In other words, ES6 classes are just special functions. So we cannot use class features in JavaScript classes.</p><p id="cd71">Class components play an important role in Error handling. Because Class Component only supports the Error Boundaries lifecycle methods <a href="https://reactjs.org/docs/react-component.html#static-getderivedstatefromerror"><code>static getDerivedStateFromErro</code>r()</a> or <a href="https://reactjs.org/docs/react-component.html#componentdidcatch"><code>componentDidCatc</code>h()</a>.</p><p id="be57">Nothing is better, because both have pros and cons. But class components are important to understand React flow and lifecycle methods.</p><p id="a897">The new learner should practice React using class components. Once they are familiar with class components, they can learn and use functional components.</p><p id="263c">Thank you for reading! Feel free to comment with your feedback and share the missing differences between class components and functional components.</p><p id="0fe9"><b>References</b></p><div id="c722"><pre><span class="hljs-symbol">https:</span>//reactjs<span class="hljs-meta">.org</span>/docs/react-component.html</pre></div><div id="f3b1"><pre><span class="hljs-symbol">https:</span>//reactjs<span class="hljs-meta">.org</span>/docs/components-<span class="hljs-keyword">and</span>-props.html</pre></div><div id="6773"><pre><span class="hljs-symbol">https:</span>//reactjs<span class="hljs-meta">.org</span>/docs/state-<span class="hljs-keyword">and</span>-lifecycle.html</pre></div><div id="27ce"><pre><span class="hljs-symbol">https:</span>//reactjs<span class="hljs-meta">.org</span>/docs/higher-order-components.html</pre></div><div id="b54f"><pre>https:<span class="hljs-regexp">//</span>www.twilio.com<span class="hljs-regexp">/blog/</span>react-choose-functional-components</pre></div><div id="116b"><pre>https:<span class="hljs-regexp">//</span>blog.logrocket.com<span class="hljs-regexp">/handling-javascript-errors-react-error-boundaries/</span></pre></div><h2 id="a212">Further Reading</h2><div id="b4aa" class="link-block"> <a href="https://bit.cloud/blog/composable-link-component-that-works-in-any-react-meta-framework-l7i3qgmw"> <div> <div> <h2>Composable Link Component that Works in Any React Meta-Framework</h2> <div><h3>Bit's Link Component is a component that is agnostic to the environment it is running in. You can use this link with…</h3></div> <div><p>bit.cloud</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*jirjpurvwexuREXO)"></div> </div> </div> </a> </div><p id="e520"><i>More content at <a href="https://plainenglish.io/"><b>PlainEnglish.io</b></a>. Sign up for our <a href="http://newsletter.plainenglish.io/"><b>free weekly newsletter</b></a>. Follow us on <a href="https://twitter.com/inPlainEngHQ"><b>Twitter</b></a></i>, <a href="https://www.linkedin.com/company/inplainenglish/"><b><i>LinkedIn</i></b></a><i>, <a href="https://www.youtube.com/channel/UCtipWUghju290NWcn8jhyAw"><b>YouTube</b></a>, and <a href="https://discord.gg/GtDtUAvyhW"><b>Discord</b></a>. Interested in Growth Hacking? Check out <a href="https://circuit.ooo/"><b>Circuit</b></a>.</i></p></article></body>

Which is Better? Class Component Or Functional Component in React?

Differences between functional components and class components in React.

Photo by Possessed Photography on Unsplash

When I start my React project, my first question is whether to use class components or functional components. Another option is to use both on the project. I hope everyone uses both components in their projects.

React lets you define components as classes or functions.

Before finding the better option, we are going to create class components and functional components.

When creating a React component, the component’s name MUST start with an upper case letter.

Class Component

To define a React component class, your class needs to extend with React.Component.

The render() method must be defined in the class component. Other React.Component methods are optional like constructor() componentDidMount(), etc.

class Hello extends React.Component {
  render() {
    return <h1>Hello World!</h1>;
  }
}
  
const element = <Hello />;
ReactDOM.render(
  element,
  document.getElementById('root')
);

Try it on CodePen

Functional Component

Here we going to change the above class component into a functional component.

function Hello() {
  return <h1>Hello World!</h1>;
}
  
const element = <Hello />;
ReactDOM.render(
  element,
  document.getElementById('root')
);

Functional components are easy to write with less code and easier to understand. Because it is just a plain JavaScript function that returns JSX.

Try it on CodePen

Differences between functional components and class components

We go through each difference between class components and functional components.

  • 1. Components Rendering
  • 2. Handling Props
  • 3. Handling States
  • 4. Lifecycle Methods
  • 5. Accessing Components Children
  • 6. Higher-Order Components
  • 7. Error Boundaries

1. Components Rendering

In the class component, the render() method is used for rendering the JSX by extending React.Component

The functional component is just a plain JavaScript function that returns JSX.

The first two programs are a perfect example of component rendering.

// Class component
class Hello extends React.Component {
  render() {
    return <h1>Hello World!</h1>;
  }
}
  
//Function component
function Hello() {
  return <h1>Hello World!</h1>;
}
  
//Function component with Arrow function
Hello = () => {
  return <h1>Hello World!</h1>;
}

Winner: Functional Component

Functional component creation is more simple by using the arrow function. A plain JavaScript function is used as a functional component. No more render method.

2. Handling Props

The props stands for properties and is passed into the React component. It’s also used for passing data from one component to another. Read more on the official React documentation.

Class component with Props

this.props used to access our name props.

class Hello extends React.Component {
  render() {
    return <h1>Hello {this.props.name}!</h1>;
  }
}
  
const element = <Hello name="World"/>;
ReactDOM.render(
  element,
  document.getElementById('root')
);

Try it on CodePen

Functional component with Props

The valid React functional component should have one argument for the function. The props argument will have all the component props like props.name.

function Hello(props) {
  return <h1>Hello {props.name}!</h1>;
}
   
const element = <Hello name="World" />;
ReactDOM.render(
  element,
  document.getElementById('root')
);

Try it on CodePen

Winner: Functional Component

No worries about the this keyword. The syntax is clean and simple, it’s a winner.

3. Handling State

state is a built-in object of React component, it is used to control the component behaviors. When the state object changes, the component will be re-renders.

Class component with state

class Timenow extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }
  
  render() {
    return(
      <div>
        <h1>Hello {this.props.name}!</h1>
        <h2>Time Now {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
  
const element = <Timenow name="World"/>;
ReactDOM.render(
  element,
  document.getElementById('root')
);

Try it on CodePen

The class components constructor method is used to initialize the state values.

Functional component with state

In the functional component, the state is handled using the useState Hook.

Hooks are a new addition to React 16.8. They let you use state and other React features without writing a class.

The functional component doesn't have this, so we can’t assign or read this.state. Instead, we call the useState Hook directly inside our functional component.

function Timenow(props) {
  const [date, setDate] = React.useState(new Date());
  return (
    <div>
      <h1>Hello {props.name}!</h1>
      <h2>Time Now {date.toLocaleTimeString()}.</h2>
    </div>
  );
}
  
const element = <Timenow name="World" />;
ReactDOM.render(
  element,
  document.getElementById('root')
);

Try it on CodePen

Winner: Functional Component

The state initialization is done by using the useState hook. No constructor method is required.

4. Lifecycle Methods

In React, each component has several lifecycle methods, this method helps you to run code at particular times in the process. Click here to view the React lifecycle diagram.

Class Component with Lifecycle Methods

The below clock class component is a perfect example of implementing lifecycle methods.

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }
  
  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }
  
  componentWillUnmount() {
    clearInterval(this.timerID);
  }
  
  tick() {
    this.setState({
      date: new Date()
    });
  }
  
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
  
ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

Try it on CodePen

Functional Component with Lifecycle Hook Methods

We converted above the clock class component into a functional component using the useEffect hook.

The useEffect return method is used to clean up.

function Clock(props) {
  const [date, setDate] = React.useState(new Date());
  
  React.useEffect(() => {
    var timerID = setInterval(() => tick(), 1000);
    
    return function cleanup() {
      clearInterval(timerID);
    };
  });
    
  function tick() {
    setDate(new Date());
  }
  
  return (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {date.toLocaleTimeString()}.</h2>
    </div>
  );
}
  
ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

Try it on CodePen

Winner: Class Component

The functional component useEffect is confusing due to using the same hook for all the lifecycle methods. In the class component, we can directly use the methods componentDidMount, componentWillUnmount, etc.

5. Accessing Components Children

The special children prop is used to access the component inside content or component like inside content.

Class Component

this.props.children is used for class components.

class Layout extends React.Component {
  render() {
   return(
      <div>
        <h1>Hello {this.props.name}!</h1>
        <div>{this.props.children}</div>
      </div>
     );
  }
}
  
const element = <Layout name="World">This is layout content</Layout>;
ReactDOM.render(
  element,
  document.getElementById('root')
);

Try it on CodePen

Functional Component

Just props.children is used in functional components to access the children's content.

function Layout(props) {
  return(
    <div>
      <h1>Hello {props.name}!</h1>
      <div>{props.children}</div>
    </div>
  );
}
  
const element = <Layout name="World">This is layout content</Layout>;
ReactDOM.render(
  element,
  document.getElementById('root')
);

Try it on CodePen

Winner: Class & Functional Component

Both use the same props.children to access the component children. In addition, we need to use the this keyword.

6. Higher-Order Components

A higher-order component (HOC) is an advanced technique in React for reusing component logic. HOC is a pure function, so it only returns a new component.

Higher-order component is a function that takes a component and returns a new component.

HOC with Class Component

function classHOC(WrappedComponent) {
  return class extends React.Component{
    render() {
      return <WrappedComponent {...this.props}/>;
    }
  }
}
  
const Hello = ({ name }) => <h1>Hello {name}!</h1>;
const NewComponent = classHOC(Hello);
  
const element = <NewComponent name="World" />;
ReactDOM.render(
  element,
  document.getElementById('root')
);

Try it on CodePen

HOC with Functional Component

function functionalHOC(WrappedComponent) {
  return (props) => {
    return <WrappedComponent {...props}/>;
  }
}
  
const Hello = ({ name }) => <h1>Hello {name}!</h1>;
const NewComponent = functionalHOC(Hello);
  
const element = <NewComponent name="World" />;
ReactDOM.render(
  element,
  document.getElementById('root')
);

Try it on CodePen

Winner: Functional Component

To create HOC, we should use the JavaScript function (classHOC, functionalHOC). Don’t Use HOCs inside the render method. Inside the function, we can use a class or functional components.

7. Error Boundaries

Error boundaries are React components used to handle JavaScript errors in React components. So we can catch JavaScript runtime errors in our components and display a fallback UI.

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.

If static getDerivedStateFromError() or componentDidCatch() lifecycle methods used means that the class component becomes an error boundary. Use static getDerivedStateFromError() to render a fallback UI after an error has been thrown. Use componentDidCatch() to log error information.

Error boundaries work as a JavaScript catch {} block, but for components.

Simple example with error boundaries

class ErrorCounter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {error: null, errorInfo: null};
  }
  
  componentDidCatch(error, errorInfo) {
    // Catch errors in any components below and re-render with error message
    this.setState({
      error: error,
      errorInfo: errorInfo
    })
    // You can also log error messages to an error reporting service here
  }
  
  refreshPage() {
    history.go(-1)
  }
  
  render() {
    if (this.state.errorInfo) {
      // Error path
      return (
        <div>
          <h2>Something went wrong.</h2>
          <details style={{ whiteSpace: 'pre-wrap' }}>
            {this.state.error && this.state.error.toString()}
            <br />
            {this.state.errorInfo.componentStack}
          </details>
          <hr />
          <button onClick={this.refreshPage}>
            Refresh Page
          </button>
        </div>
      );
    }
    // Normally, just render children
    return this.props.children;
  }
};
class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { counter: 0 };
    this.handleClick = this.handleClick.bind(this);
  }
  
  handleClick() {
    this.setState(({counter}) => ({
      counter: counter + 1
    }));
  }
  
  render() {
    if (this.state.counter === 3) {
      // Simulate a JS error
      throw new Error('I crashed!');
    }
    return(
      <div>
        <h1>{this.state.counter}</h1>
        <button onClick={this.handleClick}>+</button>
      </div>
    );
  }
}
  
ReactDOM.render(
  <ErrorCounter>
    <Counter />
  </ErrorCounter>,
  document.getElementById('root')
);

Try it on CodePen

Winner: Class Component

Currently, only class components can be Error Boundaries.

Conclusion: Which is better?

Nowadays most apps use functional components due to their simplicity, ease of use, and understanding. Also, functional components have become very famous after hooks were introduced in React v16.8.

Lifecycle methods in functional components are easy to use thanks to hooks.

Class components are hard to understand for new people who don’t have a background in ES6 JavaScript where classes were introduced.

Unlike other programming languages such as Java, PHP, and C#, JavaScript classes are syntactic sugar over the prototypal inheritance. In other words, ES6 classes are just special functions. So we cannot use class features in JavaScript classes.

Class components play an important role in Error handling. Because Class Component only supports the Error Boundaries lifecycle methods static getDerivedStateFromError() or componentDidCatch().

Nothing is better, because both have pros and cons. But class components are important to understand React flow and lifecycle methods.

The new learner should practice React using class components. Once they are familiar with class components, they can learn and use functional components.

Thank you for reading! Feel free to comment with your feedback and share the missing differences between class components and functional components.

References

https://reactjs.org/docs/react-component.html
https://reactjs.org/docs/components-and-props.html
https://reactjs.org/docs/state-and-lifecycle.html
https://reactjs.org/docs/higher-order-components.html
https://www.twilio.com/blog/react-choose-functional-components
https://blog.logrocket.com/handling-javascript-errors-react-error-boundaries/

Further Reading

More content at PlainEnglish.io. Sign up for our free weekly newsletter. Follow us on Twitter, LinkedIn, YouTube, and Discord. Interested in Growth Hacking? Check out Circuit.

JavaScript
React
Web Development
Front End Development
Javascript Development
Recommended from ReadMedium