Boost Your React Skills: Essential Tips for Every Developer

Boost Your React Skills: Essential Tips for Every Developer

ยท

7 min read

Table of contents

Photo by Rahul Mishra Unsplash

In this article, I'm going to reveal some super amazing React application tips that will totally boost your performance and elevate your code-writing skills! I'll be sharing all the cool stuff I know and use, but if you have even more incredible tips, don't hesitate to drop them in the comment section below! Let's dive right in and rock this! ๐ŸŽ‰

  1. Custom Hooks: Custom hooks have this cool naming pattern: "useSomething" - so you know they're React hooks right away! You can whip them up using the built-in useState, useEffect, and useContext hooks. The best part? You can create reusable bits of logic that can be shared throughout your entire app! ๐Ÿš€ So, go ahead and give Custom Hooks a try - you'll be amazed at how much they can boost your coding skills! Let's look at an example

     import { useState } from 'react'
     export const useCounter = () => {
         // this hook is to create a counter
    
         // First:  create our counter state
         const [counter, setCounter] = useState(0)
    
         // second: write the function to increment counter
         const handleIncrementCounter = (e: Event) => {
             e.preventDefault();
    
             setCounter((prev:boolean) => prev + 1);
         }
    
         // third: create a return statement. The return statement is used to                            define what the hook will return when the hook is called
         return { counter, handleIncrementCounter  }
     }
    

    Using it in our App.tsx file

     import React from 'react'
    
     const App = () => {
         const { counter, handleIncrementCounter } = useCounter();
         return (
             <>
                    <p>{counter}</p>
                    <button onClick={handleIncrementCounter}>
                         Increment Me!                             
                     </button>
             </>
         )
     }
    

    We just created a fun little counter app together! ๐Ÿ˜Š

  2. Code-Splitting and Lazy Loading: Code Splitting is a technique used in React to split the codebase into chunks that can be loaded on demand, instead of loading the entire application upfront. This will reduce the load time and overall performance of the application. This may be hard to understand so let me break it down by using an example or can I say code-split it ๐Ÿ˜….

    So, imagine you're making an app with an admin page and a regular user page, right? You don't want users to load all the admin stuff they don't need, and the same goes for admins. That's where code-splitting comes in handy, my friend! ๐Ÿ˜„

    Let us see an example of how we can implement code splitting in React.

     import React, { lazy, Suspense } from 'react';
    
     const AdminPage = lazy(() => import('./AdminPage'));
     const RegularUserPage = lazy(() => import('./UserPage'));
    
     function App() {
       return (
         <div>
           <h1>Welcome to My App</h1>
           <Suspense fallback={<div>Loading...</div>}>
             {isAdmin ? <AdminPage /> : <UserPage />}
           </Suspense>
         </div>
       );
     }
    
     export default App;
    
  3. Higher-Order Components (HOCs): Higher-order components are functions that take a component ad return a new component with additional functionality. They allow you to reuse your code and keep your components clean.

    Let's look at an example

     import {Redirect} from 'react-router-dom'
    
     const withAuth = (Component) => {
         const AuthenticatedComponent = () =>  {
         // this is to check if the user is authenticated
         const isAuthenticated = true;
    
         if (isAuthenticated) {
                 // when user is component, it will render this
                   return <Component {...props}/>
             }
         else {
             // this will redirect the user to the login page if not authenticated
                 return <Redirect to='/login' />
             }
         }
     }
    

    Now let's apply the Higher Order component we created

     const Profile = () => {
         return (
             <>
                 <p>This is my Profile! My name is Coding Pastor</p>
             </>
         )
     }
    
     // import withAuth
     const AuthenticatedApp = withAuth(Dashboard)
    
     const App = () => {
       return (
         <Router>
           <Switch>
             <Route exact path="/" component={Home} />
             <Route path="/dashboard" component={AuthenticatedDashboard} />
             <Route path="/login" component={Login} />
           </Switch>
         </Router>
       );
     };
    

    We wrapped the "Profile" component with the "withAuth" Higher-order component. This will ensure that only authenticated users can access the Profile page. Users that are not authenticated will be redirected to the login page.

  4. Context API: Context API is a way to share data between components without passing props down through the entire component. It allows you to create a global state that can be accessed by any component in your application. It is the cure for prop drilling. Sometimes you want a state to be general and accessible throughout your whole application, instead of passing down props and digging through your application, you can use Context API to create a global state. Let's see how we can do that.

    For this example, we will create a context that stores users' data after authentication. Creating a theme context is too common on the internet. Let's do something uncommon.

     import React, { createContext, useState } from 'react';
    
     export const AuthContext = createContext();
    
     const AuthProvider = ({ children }) => {
       const [isAuthenticated, setIsAuthenticated] = useState(false);
       const [userData, setUserData] = useState(null);
    
       const login = (userData) => {
         setIsAuthenticated(true);
         setUserData(userData);
       };
    
       const logout = () => {
         setIsAuthenticated(false);
         setUserData(null);
       };
    
       return (
         <AuthContext.Provider value={{ isAuthenticated, userData, login, logout }}>
           {children}
         </AuthContext.Provider>
       );
     };
    
     export default AuthProvider;
    
     import React from 'react';
     import AuthProvider from './AuthProvider';
     import LoginPage from './LoginPage';
     import ProfilePage from './ProfilePage';
    
     function App() {
       return (
         <AuthProvider>
           <LoginPage />
           <ProfilePage />
         </AuthProvider>
       );
     }
    
     export default App;
    

    To access the user data;

     import React, { useContext } from 'react';
     import { AuthContext } from './AuthProvider';
    
     function ProfilePage() {
       const { userData } = useContext(AuthContext);
    
       return (
         <div>
           <h1>Welcome, {userData.username}!</h1>
           <p>Email: {userData.email}</p>
         </div>
       );
     }
    
     export default ProfilePage;
    
  5. React Hooks: This one is very common and used by every React developer., Examples of popular react hooks are the useState hooks, useEffect, useReducer, and more. React hooks provide a simpler and more concise way to manage state and lifecycle methods in your components. We already used the useState hook above. let's see others. We will not be able to touch everything

    1. useEffect Hook: The useEffect hook enables side effects in functional components, such as data fetching, event subscribing, or DOM updates. It takes a function and an optional dependencies array, executing the function after each render based on the dependencies. Use it wisely to prevent performance issues or bugs.

       const [data, setData] = useState(null);
      
       useEffect(() => { 
       const fetchData = async () => { 
       const response = await fetch('https://api.example.com/data'); 
       const result = await response.json(); setData(result); 
       };
      
       fetchData(); }, []);
      
       // from this code above, we are trying to render the data from the fetchData to the page.
      
    2. useReducer Hook: The useReducer hook manages complex state in components, providing more flexibility than useState. It requires a reducer function and initial state and returns an array with the current state and a dispatch function. While powerful, it can be more challenging than useState, especially for React beginners.

       const initialState = { count: 0 };
      
       function reducer(state, action) {
         switch (action.type) {
           case 'increment':
             return { count: state.count + 1 };
           case 'decrement':
             return { count: state.count - 1 };
           default:
             throw new Error();
         }
       }
      
       function Counter() {
         const [state, dispatch] = useReducer(reducer, initialState);
      
         return (
           <>
             Count: {state.count}
             <button onClick={() => dispatch({ type: 'increment' })}>+</button>
             <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
           </>
         );
       }
       // This is a count application with useReducer
      
    3. useRef: The useRef hook is a super helpful tool that lets you create and manage changeable references right inside your functional components. It's often used for directly accessing DOM elements or keeping values that stay the same across renders without making your component re-render. Pretty cool, right?

       import React, { useRef } from 'react';
      
       function TextInput() {
         const inputRef = useRef(null);
      
         const focusInput = () => {
           inputRef.current.focus();
         };
      
         return (
           <div>
             <input ref={inputRef} type="text" />
             <button onClick={focusInput}>Focus Input</button>
           </div>
         );
       }
      
       export default TextInput;
      
    4. useMemo: useMemo is a fantastic React hook that boosts the performance of your app by remembering the outcome of a function, so you don't have to do needless re-calculations. It needs two things: a function that gives you a value, and an array of dependencies. The magic happens when useMemo only re-does the calculation if any dependencies change. This is super handy for complex calculations or when a component keeps rendering often.

       const memoizedResult = useMemo(() => {
         return expensiveCalculationFunction(a, b);
       }, [a, b]);
      
    5. useCallback: useCallback is another react hook that memorizes a callback function, preventing unnecessary re-creating of the function. It takes two arguments: The callback function and an array of dependencies. useCallback will return the memoized version of the callback function, which will only change if one of the dependencies has changed. This is useful for optimizing performance, especially when passing callbacks to child components on a frequently rendered component.

       const memoizedCallback = useCallback(() => {
         doSomethingWith(a, b);
       }, [a, b]);
      

      The use Callback hook is similar to the useMemo hook since they boost the performance of the application. The difference between the two hooks is that while the useMemo hook memoizes the result of a function, useCallback hook memoizes a callback function.

Conclusion

In conclusion, WOW! Utilizing React features like Custom Hooks, Code-Splitting, Higher-Order Components, Context API, and various hooks such as useState, useEffect, useReducer, useRef, useMemo, and useCallback can MASSIVELY enhance your application's performance and code quality! Embrace these AWESOME techniques to not only make your code super efficient but also skyrocket your skills as a React developer! Thank you for reading and HAPPY CODING! ๐Ÿš€๐ŸŽ‰

ย