SSW Foursquare

Rules to Better React - 15 Rules

Want to build your web application in React? Check SSW's React consulting page.

  1. Do you know why React is great?

    There are so many open-source platforms for making the front-end web application development easier, some people like Angular, some people like React. Let us take a look at the benefits of React.

    Simplicity

    ReactJS is just simpler to grasp right away. The component-based approach, well-defined lifecycle, and use of just plain JavaScript make React very simple to learn, build a professional web (and mobile applications), and support it. React uses a special syntax called JSX which allows you to mix HTML with JavaScript. This is not a requirement; Developers can still write in plain JavaScript but JSX is much easier to use.

    Easy to learn

    Anyone with a basic previous knowledge in programming can easily understand React while Angular and Ember are referred to as Domain specific Language, implying that it is difficult to learn them. For React you just need basic knowledge of CSS and HTML.

    Native Approach

    React can be used to create mobile applications (React Native). And React is a diehard fan of reusability, meaning extensive code reusability is supported. So at the same time we can make IOS, Android and Web applications.

    Data Binding

    React uses one-way data binding and an application architecture called Flux controls the flow of data to components through one control point – the dispatcher. It's easier to debug self-contained components of large ReactJS apps.

    Performance

    React does not offer any concept of a built-in container for dependency. You can use Browserify, RequireJS, EcmaScript 6 modules which we can use via Babel, ReactJS-di to inject dependencies automatically.

    Testability

    ReactJS applications are super easy to test. React views can be treated as functions of the state, so we can manipulate state we pass to the ReactJS view and take a look at the output and triggered actions, events, functions, etc.

    Great Developer Tools

    Developer toolset is another important factor when you are choosing a development platform. There are 2 great tools you should be aware of:  React Developer Tools  and  Redux Developer Tools.  Both can be installed as Chrome extensions.

    References

  2. Do you know the best learning resources for React?

    Here are the best collection of resources for React.

    Free Resources

    Training Courses

    Books

    Free Events

    • Find your local JavaScript or React User Group on MeetUp
  3. Do you know how to easily start a React project?

    The old standard way to start a React project, create-react-app is no longer actively supported by Facebook, and has been removed from the official developer documentation (https://react.dev/learn/start-a-new-react-project). Therefore, it is not the best choice for starting a client-side rendered React app.

    Vite

    Vite is a reliable frontend build tool for building fast and optimised frontend web apps that has easy integration with a wide range of frontend web frameworks, and built-in Typescript support.

    Vite is much faster than using create-react-app, mainly because Vite does not use Webpack for bundling assets. It instead uses esbuild and Rollup, which are much faster and more modern tools for building great frontend web apps.

    new create react app
    Bad example: Using the create-react-app npm package

    vite
    Good example: Use Vite to generate a react-ts project

    Note: Vite requires Node version 14.18+ or 16+.

    1. Run:
    npm create vite@latest 
    1. Enter the name of your project
    2. Select "React" from the list of frameworks

    vite pick
    Figure: The framework options with Vite

    1. Then, select the "TypeScript" variant from the list

    vite pick typescript
    Figure: The variant options with Vite

    1. All done! Now navigate into the directory and run the app with the following commands:
    cd {{ PROJECT_NAME }}
    npm install 
    npm run dev

    NextJS

    As per the official React docs (https://react.dev/learn/start-a-new-react-project), the recommended way to start a new React project is with NextJS.

    It is recommended in NextJS official docs (https://nextjs.org/docs/pages/api-reference/create-next-app) to start a new NextJS project by using:

    npx create-next-app@latest

    Developers can then manually choose how they want to set up their NextJS app.

    Gatsby

    As per the Gatsby docs (https://www.gatsbyjs.com/docs/quick-start/), the most effective approach to start a new Gatsby site is by executing the following command:

    npm init gatsby

    Through the provided prompts, you can also select your preferred language (JavaScript or TypeScript), CMS, and styling system that you intend to use.

  4. Tools - Do you know the best Build Tool for React?

    Creating a Production Build of a React project is complicated, you need great tools.

    Webpack

    Webpack is a module bundler. It packs CommonJs/AMD modules.

    Create React App

    npm run build

    Create React App uses Webpack under the hood.npm run build creates a build directory with a production build of your app.

  5. Do you know the best package manager for React?

    When it comes to package management in JavaScript, 3 major players dominate the scene. Have you considered which one offers the best synergy with your development goals?

    While all three package managers have their strengths, the choice often boils down to the specific needs of a project and the preferences of the development team. Yarn offers a balanced blend of speed and reliability, npm provides familiarity and wide adoption, and pnpm shines in terms of efficiency and space-saving.

    1. npm

    npm logo

    Overview: npm has long been the backbone of JavaScript development. It is the default package manager for the Node.js JavaScript runtime environment and has been widely adopted by the developer community.

    Notable Incident: In 2016, the removal of the "left-pad" package from npm caused widespread issues, making developers reconsider their reliance on the platform.

    Strengths:

    • Mature & Widely Adopted: npm has a long history and vast package repository.
    • Integrated with Node.js: Being the default for Node.js makes it straightforward for many developers.

    yarn logo

    Overview: Introduced by Facebook, Yarn was developed as an alternative to npm, addressing some of the issues developers faced with npm.

    Strengths:

    • Speed: Yarn is known for its faster package installation times compared to npm.
    • Offline Support: Once you've installed a package with Yarn, it can be reinstalled without an internet connection, preventing potential disruptions like the "left-pad" incident.
    • Deterministic Installs: Yarn generates a lock file to ensure consistent installations across different systems.

    pnpm logo

    Overview: pnpm is a newer entrant in the package manager arena, but it brings unique features to the table.

    Strengths:

    • Efficiency: pnpm's installation speed is even faster than Yarn's and npm's due to its unique approach of linking packages from a global cache.
    • Disk Space Savings: By linking to a global cache, pnpm ensures packages aren't redundantly stored across multiple projects.
    • Strict Package Isolation: pnpm ensures that projects get exactly what they need and no additional, potentially conflicting packages.
  6. Do you know the best practice for managing state?

    State management is complex and time-consuming. The redux pattern helps resolve this issue.

    maintaining state
    Figure: Bad example - Maintaining state on individual components

    redux logo
    Figure: Good example - use the redux pattern

    The 4 principles of the redux pattern

    1. The entire state of the application is represented in a single JavaScript object called a store.
    2. The store is acted upon using special functions called reducers.
    3. State is immutable and reducers are the only part of the application that can change state.
    4. Reducers are pure JavaScript functions. This means they cannot import external dependencies.

    Side Effects

    To perform operations that require external dependencies (such as communicating with a web server), we can implement side effects. These can use external dependencies but they cannot directly modify the store. They can invoke reducers to modify the store when the side effect is complete.

    Redux-Saga is a library that provides redux application side effects.

    The advantages of using Redux-Saga are:

    • Collects all asynchronous operations in one place, making the code clearer
    • Uses an ES6 feature called Generators to make asynchronous flows easy to read, write and test
    • Generators also let these asynchronous flows look like your standard synchronous code (kind of like async/await in C#). This solves “callback hell"
  7. Do you know the best example projects – React?

    There are many example projects created by the React community.  

    Below is a list of sample applications from https://reactjs.org/community/examples.html

    • Calculator Implementation of the iOS calculator built in React
    • Emoji Search Simple React app for searching emoji
    • Github Battle App Battle two Github users and see the most popular Github projects for any language.
    • React Powered Hacker News Client A React & react-router-powered implementation of Hacker News using its Firebase API.
    • Pokedex The list of Pokémon with live search
    • Shopping Cart Simple ecommerce cart application built using React
    • Progressive Web Tetris Besides a beautiful, mobile-friendly implementation of Tetris, this project is a playground for integrating and experimenting with web technologies.
    • Product Comparison Page Simple Product Compare page built in React
    • Hacker News Clone React/GraphQL Hacker News clone rewritten with universal JavaScript, using React and GraphQL.
    • Bitcoin Price Index Simple bitcoin price index data from CoinDesk API.
    • Builder Book Open source web app to write and host documentation or sell books. Built with React, Material-UI, Next, Express, Mongoose, MongoDB.
    • GFonts Space A space which allows user to play with Google fonts. Built with React, Redux and React-Router.
  8. Do you know the best libraries to fetch data in React?

    While using a regular useEffect to run when a component is loaded to fetch data is super easy, it may result in unnecesary duplicate requests for data or unexpected errors when unmounting components. It is best to use a library that can provide hooks for fetching data, as not only does it solve the above issues, but also comes with useful features such as caching, background updates, and pre-fetching.

    Below is an example of a standard data fetch in React:

    const Component = () => {
      const [data, setData] = useState({});
      const [loading, setLoading] = useState(true);
    
      useEffect(() => {
        fetch("https://jsonplaceholder.typicode.com/todos/1")
          .then(res => res.json())
          .then(json => {
            setData(json);
            setLoading(false);
          })
      }, [])
    
      return (
        {loading
          ? <> {/* Display data here */} </>
          : <p>Loading...</p>
        }
      )
    }

    Figure: The traditional way of fetching data in React

    This example is not ideal, as it means every time we reload this page component, or if we make the same request on another page, there will be an unnecessary request made instead of pulling the data from a cache.

    Below are the two recommended options that both serve effectively the same purpose in providing developers with useful hooks for fetching data. These libraries not only give developers a wide range of other features, but also reduces the amount of boilerplate code they have to write.

    TanStack Query is a feature-rich data fetching library developed by Tanstack. It can be used with existing data fetching libraries such as Axios, GraphQL packages such as graphql-request, or just plain fetch.

    Video: React Query in 100 Seconds by Fireship (2 mins)

    Here's a basic example of how you can use Tanstack Query:

    import {
      useQuery,
      QueryClient,
      QueryClientProvider,
    } from "react-query";
    
    const queryClient = new QueryClient();
    
    function useTodos() {
      return useQuery("todos", async () => {
        const res = await fetch("/api/todos");
        const json = await res.json();
        return json;
      })
    }
    
    export const Page = () => {
      const { status, data, error, isFetching } = useTodos();
    
      if (status === "error") return <div>Error loading data: {error}</div>
      if (status === "loading") return <div>Loading...</div>
    
      return (
        <QueryClientProvider client={queryClient}>
          <div>
            <div>{/* Display todos here */}</div>
            {isFetching && <p>Re-fetching data in the background...</p>}
          </div>
        </QueryClientProvider>
    }

    This code employs the useQuery hook for asynchronous data fetching and a QueryClientProvider to manage the query cache in the component tree.

    Some features of Tanstack Query:

    You can find out more about Tanstack Query at tanstack.com/query.

    SWR

    SWR is an alternative to Tanstack Query developed by Vercel, the team behind Next.js. Much like Tanstack Query, SWR is library-agnostic, meaning you can use whatever data fetching library you are comfortable with.

    Here's a basic example of how you can use the library's fetching hook:

    const fetcher = (url) => fetch(url).then(res => res.json())
    
    export const Page = () => {
      const { data, error, isLoading } = useSWR("/api/todos", fetcher);
    
      if (error) return <div>Error loading data</div>
      if (loading) return <div>Loading...</div>
    
      return <div>{/* Display todos here */}</div>
    }

    Some features of SWR:

    Note: Currently, the vast majority of SWR APIs are not compatible with the App router in Next.js 13.

    You can find out more about using SWR at swr.vercel.app.

    RTK Query

    Additionally, RTK Query, part of the Redux Toolkit, is a similar library to SWR and React Query with tight integration with Redux and seamless type-safe importing sourced from OpenAPI specifications.

    Here's a basic example of how you can use RTK Query:

    import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
    
    const todosApi = createApi({
      baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
      endpoints: (builder) => ({
        getTodos: builder.query<Array<Todo>, void>({
          query: () => 'todos',
        }),
      }),
    });
    
    const { useGetTodosQuery } = todosApi;
    
    // For use with Redux
    const todosApiReducer = todosApi.reducer;
    
    const TodoPage = () => {
      const { data, isError, isLoading } = useGetTodosQuery();
    
      if (isLoading) return <p>Loading...</p>;
      if (isError) return <p>Error fetching todos</p>;
    
      return (
        <div>{/*( Display todos here */}</div>
      );
    };

    Some features of RTK Query:

    • Seamless Redux integration: Designed as part of the Redux Toolkit, RTK Query is intrinsically designed to work with Redux, providing a cohesive data management experience. Learn more
    • OpenAPI schema code generation: Auto-generates end-to-end typed APIs based on OpenAPI schemas, drastically reducing boilerplate and ensuring type safety. Learn more
    • Caching - cache management based on endpoint and serialized arguments - learn more
    • Automatic retries - built-in mechanism to automatically retry failed queries, enhancing resilience - learn more
    • Prefetching - fetches data in anticipation of user actions to enhance UX - learn more
    • Parallel and dependent queries: Efficient handling of multiple simultaneous or dependent data fetching. Learn more

    Discover more about RTK Query in Redux Toolkit's official documentation at redux-toolkit.js.org/rtk-query/overview.

  9. Tools - Do you know the best IDE for Angular and React?

    When developing Angular or React, there are lots of choices for code editors. The best experience by far is to use Visual Studio Code.

    angular machine setup 1
    Figure: Good Example - Visual Studio Code is a free, lightweight IDE that runs on Windows, Linux and macOS. Visual Studio Code is the IDE of choice for many Angular developers and has lots of great extensions for Angular

    Many experienced teams are using Visual Studio for their C# backend and loving using Visual Studio Code for their Angular or React projects.

    The recommended extension for Visual Studio Code is Angular Essentials from John Papa.

    Angular Essentials is actually a meta-package that includes a list of great extensions for Angular Development – and this list may be updated in the future as more extensions become popular.

    See https://github.com/johnpapa/vscode-angular-essentials.

    angular machine setup 2
    Figure: Good Example – the Angular Essentials extension will install a great suite of extensions to support Angular development

    You can find more extensions at Visual Studio | Marketplace.

    Open in Visual Studio Code

    This extension is for those times where you have a project open in Visual Studio and you want to be able to quickly open it in Visual Studio Code.

    open in vscode
    Figure: Get to Visual Studio Code quickly from within Visual Studio - Open in Visual Studio Code extension

    More: Why do others love VS Code?

  10. Tools - Do you know the best Packages and Libraries to use with React?

    The whole React ecosystem improves every month. Tons of additional tools, libraries and components are released to simplify the developer’s job and minimize the required effort. 

    Starter kits

    Developers still struggle on making a decision on how to setup their React project when joining the React community. There are thousands of boilerplate projects to choose from and every boilerplate project attempts to fulfil different needs. They vary in a range of minimalistic to almost bloated projects. Here are 4 great Starter kits for React developers.

    • Vite - A modern tool for quicker development and building, compatible with different front-end frameworks, including React
    • Create React App - A popular and easy way to start React projects with minimal setup
    • Next.js - A flexible React framework that's great for making websites. It helps pages load fast and is user-friendly for developers while also providing SEO capabilities
    • Gatsby - A powerful React framework for static websites and blogs with robust static site generation capabilities and SEO optimization

    See more at Start a New React Project.

    Utility Libraries for React

    JavaScript ES6 and beyond gives you plenty of built-in functionalities dealing with arrays, objects, numbers, objects and strings. One of the most used JavaScript built-in functionalities in React is the built-in map() Array.

    • Lodash is the most widespread utility library in JavaScript. Lodash comes with a powerful set of functions to access, manipulate and compose
    • Ramda is also great utility library when leaning towards functional programming (FP) in JavaScript

    Asynchronous Requests in React

    • native fetch API - Nowadays, recent browsers implement the fetch API to conduct asynchronous requests. It uses promises under the hood
    • axios - It can be used instead of the native fetch API when your application grows in size. Another alternative is called superagent

    State Management Helpers

    • Reselect - Creates a selector where the first functions passed in compute props for a final function. If none of those props have changed, then that function is not run and the result from the previous invocation is returned. This keeps the state from needlessly causing components to re-render

    Global Serverless Deployments

    • Vercel - Makes serverless application deployment easy

    Testing

    • Jest - Testing suite that provides a click-and-check API for automated in-browser smoke tests
  11. Practices - Do you write small components?

    The Single Responsibility Principle is a well understood, and well-accepted tenet of good code design. It states that a class should do one thing, and do it well - The same applies to Components used with Frameworks such as Angular, React, Vue and Blazor.

    When designing components, keep them small, modular and reusable. For example, if you have a menu, put it into a menu component, don’t put it in your app component.

    comp 1
    Figure: Bad example - Having just 3 components for the page makes it difficult to reuse, maintain and test

    comp 2
    Figure: Good example - Splitting up the page into 11 components means they are small and targeted - and thus easy to maintain and test. Components can be reused on other pages

  12. Tools - Do you know the best UI framework for React?

    The main contenders for the best UI framework for React are:

    MATERIAL-UI https://material-ui.com

    Bootstrap https://getbootstrap.com

    Tailwind https://tailwindcss.com/

    Ant Design https://ant.design

    MATERIAL-UI

    MaterialUI is a set of React Components that Implement the Google’s Material Design Guidelines. When it comes to predefined components especially UI, one important thing we need to find is how many UI widgets are available and whether these can be customized with configurations. Material-UI has all components that you need and it is very configurable with a predefined color palette. Material UI is one of the best Reactjs based UI frameworks that have the most refined implementation of Material Design.

    Snipaste 2019 05 14 18 04 27
    Figure: MaterialUI is a set of React components that implement Google's Material Design

    Get started: react-material-ui-official-docs-example

    React Bootstrap

    Bootstrap is one of the most popular and widely used CSS frameworks. It is no surprise to have the duo of React and Bootstrap. React Bootstrap is a set of React components that implement the Bootstrap framework. React-Bootstrap currently targets Bootstrap v5.3.

    Get started: react-bootstrap-ui-official-docs-example

    Tailwind

    Tailwind is a popular utility-first CSS framework that simplifies the process of building user interfaces. It provides a comprehensive set of pre-built utility classes that can be easily combined to create responsive and flexible designs. With Tailwind, developers can quickly style their components without writing custom CSS, resulting in faster development and easier maintenance.

    Get started: tailwind-example

    Ant Design

    Ant Design React is dedicated to providing a good development experience for programmers. An enterprise-class UI design language and React-based implementation. Ant Design is a set of high-quality React components out of the box which is written in TypeScript . It supports a browser, server-side rendering, and Electron environments have many components and even a tutorial with Create React App

    Get started: ant-design-example

  13. Do you use Typescript?

    Typescript is the best choice when writing Angular and React applications. Angular is even written in Typescript itself! 

    Video: Typescript in 100 Seconds

    ✅Advantages of Using TypeScript

    1. Type Safety

      • Error detection: - Identify and correct errors during the build phase, preventing runtime surprises.
      • Top-notch tooling - Utilize enhanced features like autocomplete, Intellisense, efficient code navigation, and linting.
      • Streamlined refactoring - Superior tooling simplifies refactoring compared to plain JavaScript.
      • Embrace the latest - Leverage the latest language innovations for cleaner, more concise code.
    2. Enhanced Code Expressivity

      • Syntax sugar - Improves code readability and intuitiveness.
      • Automatic imports - Streamline module integrations.
    3. Wider Browser Support

      • Multi-version targeting - Use a single TypeScript codebase across various JavaScript versions (e.g., ES5, ES6).
    4. Boosted Code Confidence and Maintainability

      • Minimized risk - Reduce the likelihood of bugs and bolster code reliability.
      • Time efficiency - Dedicate less time to unit tests with increased code trustworthiness.
      • Early bug detection - Identify and rectify issues early.
      • Clarity - Craft cleaner, more transparent code.

    ❌ Disadvantages of TypeScript

    1. Learning curve - Developers unfamiliar with statically typed languages might face an initial learning challenge.
    2. Compilation step - An additional step to compile TypeScript to JavaScript can sometimes be perceived as a minor inconvenience.
    3. Integration with some libraries - Not all JavaScript libraries come with TypeScript definitions by default.

    🔍 Explore TypeScript further at the official TypeScript website.

    🎥 If you prefer video content, have a look at SSW TV Videos on TypeScript.

  14. Tools - Do you use Nx to manage your huge JavaScript solution?

    One of the main problems working on a huge monorepo solution is usually the development experience and the build time.Nx is one of many tools that can improve this experience in JavaScript projects.

    The amount of code that needs to be processed by the compiler scales proportionally with the solution size. Hence, the compile time will grow naturally as the solution grows in size.This surely affects both the development experience and the team's velocity, leaving both developers and stakeholders unhappy.

    Nx is a JavaScript build system that aims to make developing on monorepo solution easier and faster.Nx offers the following features:

    Currently, Nx supports many frameworks, such as Angular, React, Node, and many more.

    Adding a tool such as Nx to a project will obviously add another moving parts to the solution, so it's a good idea to know the advantages and disadvantages of Nx.

    Advantages:

    Disadvantages:

    • Additional external dependency to be maintained
    • Learning curve
    • Only supports JavaScript projects

    Consider using Nx in a project when your solution:

    • Is a JavaScript monorepo
    • Is medium to large sized
    • Contains multiple projects
    • Share codes between projects
    • Has slow build time
  15. Do you use these useful React Hooks?

    React Hooks streamline state management and lifecycle processes in functional components, resulting in cleaner, more performant code. These are the most common and useful hooks that you should use in your React project:

    1. useState: Managing Local State 🧠

    The useState hook lets you add state to functional components. Call useState at the top level of your component to declare one or more state variables.

    import { useState } from 'react';
    
    export default function Counter() {
      const [count, setCount] = useState(0);
    
      function handleClick() {
        setCount(count + 1);
      }
    
      return (
        <button onClick={handleClick}>
          You pressed me {count} times
        </button>
      );
    }

    Figure: Using useState for a counter component

    Naming Convention: It's a common convention to name state variables using the pattern [count, setCount] with array destructuring.

    useState returns an array with exactly two items:

    1. The current state of this state variable, initially set to the initial state you provided.
    2. A function that lets you update its value.
    • Updating Objects and Arrays: Manage and adjust objects and arrays in the state. Remember, always create new references instead of mutating
    • Avoiding Recreating the Initial State: Ensure the initial state is set only once, avoiding recalculations in subsequent renders
    • Resetting State with a Key: Reset the component's state by altering its key
    • Storing Information from Previous Renders: On rare occasions, adjust state as a reaction to a rendering process

    ⚠️ Pitfalls

    • State Updates: A change in state doesn't instantly reflect within the current executing code. It determines what useState will return in future renders
    • Initializer Function: When you pass a function to useState, it gets called only during the initialization phase
    • State Updates with Functions: When deriving new state values from the previous state, it's better to use an updater function as an argument of the setter function instead of the new value i.e. setObj(prev => { key: value ...prev }. This ensures you're working with the most up-to-date state

    Read more about useState on the offical docs

    2. useEffect: Side Effects & Lifecycles 🔄

    In React functional components, useEffect serves as your toolkit to execute side effects, reminiscent of lifecycles in class-based components. Through dependencies, you can control when these effects run, granting granular control over side effect operations.

    import { useState, useEffect } from 'react';
    
    export default function Counter() {
      const [count, setCount] = useState(0);
    
      useEffect(() => {
        const intervalId = setInterval(() => {
          setCount(c => c + 1); 
        }, 1000);
        return () => clearInterval(intervalId);
      }, []); 
    
      return <h1>{count}</h1>;
    }

    Figure: useEffect Count example

    It's similar in concept to Angular's ngOnChanges lifecycle hook. While ngOnChanges in Angular detects and reacts to changes in input-bound properties, React's useEffect serves a broader purpose.

    • External System Connection: Link React components to other systems like APIs, networks, or third-party libraries
    • Custom Hooks Encapsulation: Nest your effect logic inside custom hooks for clarity and better structure
    • Non-React Widget Control: Bridge the gap between React components and non-React widgets
    • Data Fetching: While useEffect can fetch data, it's optimal to use the framework's standard mechanisms or custom hooks
    • Reactive Dependencies: Identify reactive items (e.g., props, state) that influence your effect. When these alter, the effect kicks in again
    • State Updates: Adjust state values referencing their former versions using useEffect
    • Access to Recent Props & State: useEffect ensures the most recent props and state are at your disposal
    • Distinct Server/Client Content: With effects operational solely on the client, you can orchestrate unique content for server and client views

    ⚠️ Pitfalls

    • Placement: Ensure useEffect remains at the top level of your components/custom hooks. Bypass calling it within loops or conditionals
    • Avoid Overuse: Turn to useEffect mainly for external synchronization
    • Strict Mode Nuances: In strict mode, a preliminary setup+cleanup cycle, exclusive to development, verifies your cleanup's alignment with your setup
    • Dependencies Oversight: If dependencies comprise inner-component objects or functions, they might trigger frequent effect repetitions
    • Visual Effects Caution: A visual glitch before an effect suggests useLayoutEffect might be a better pick
    • Server Rendering: useEffect is client-centric and doesn't engage during server-side rendering

    Read more about useEffect on the offical docs

    3. useContext: Using Context Seamlessly 🌍

    useContext is a pivotal React Hook, giving you the power to both read and subscribe to context values right within your component.

    import { createContext, useContext } from 'react';
    
    // Create a context
    const ThemeContext = createContext({
      background: 'light',
      foreground: 'dark',
    });
    
    function ThemedButton() {
      const theme = useContext(ThemeContext);
      return (
        <button style={{ background: theme.background, color: theme.foreground }}>
          I am styled by theme context!
        </button>
      );
    }
    
    export default function App() {
      return (
        <ThemeContext.Provider value={{ background: 'black', foreground: 'white' }}>
          <ThemedButton />
        </ThemeContext.Provider>
      );
    }

    Figure: A Themed button example using useContext

    • Reading and Subscribing to Context: Directly access and subscribe to context values straight from your component
    • Passing Data Deeply: Bypass manual prop-drilling, letting you transmit data deeply through the component hierarchy
    • Updating Data Passed via Context: Easily modify context values and integrate them with state for seamless updates across various components
    • Specifying a Fallback Default Value: If no context provider is present upstream, useContext will resort to the default value established during context creation
    • Overriding Context: For tailored requirements, override the context in specific parts of the component tree by enveloping it in a provider with a distinct value
    • Optimizing Re-renders: Amplify performance when transferring objects or functions through context using techniques such as useCallback and useMemo

    ⚠️ Pitfalls

    • Provider Position: The context search strategy employed by useContext is top-down, always eyeing the nearest provider. It disregards providers present in the invoking component
    • Re-rendering Children: Context shifts compel React to re-render all child components stemming from the provider with a changed value. The assessment hinges on the Object.is comparison, meaning that even memo cannot fend off updates stemming from refreshed context values
    • Duplicate Modules: Be wary of build systems churning out duplicate modules (e.g., due to symlinks). This can disintegrate context as both the provider and consumer must be the exact same object, passing the === comparison test
    • Provider Without a Value: An absent value prop in a provider translates to value={undefined}. The default from createContext(defaultValue) comes into play only when there's a complete absence of a matching provider
    • Provider Cannot be Accessed: If useContext is used in a component that is not wrapped by a provider, this can cause client-side errors as the value accessed will be null

    Read more about useContext on the offical docs

    4. useRef: Direct DOM Access & Persistent References 🎯

    The `useRef hook in React allows you to access and interact with DOM elements or maintain a mutable reference to values across renders without triggering a re-render.

    import { useRef } from 'react';
    
    function MyComponent() {
      const inputRef = useRef(null);
    
      function handleFocus() {
        inputRef.current.focus();
      }
    
      return (
        <>
          <input ref={inputRef} />
          <button onClick={handleFocus}>Focus the input</button>
        </>
      );
    }

    Figure: On button click focus the input using useRef

    • Referencing a Value: `useRef lets you reference a value that doesn't affect the rendering of your component
    • Manipulating the DOM: By attaching the returned ref object as a ref attribute to a JSX node, React sets its current property to that DOM node, allowing direct DOM manipulations
    • Avoiding Recreating the Ref Contents: React preserves the initial ref value and doesn't recreate it during subsequent renders. This is beneficial for computationally expensive values
    • Storing Information from Previous Renders: Refs persist their data across renders and can store information that doesn’t initiate a re-render
    • Accessing Another Component's DOM Nodes: With React.forwardRef(), you can expose refs of the DOM nodes inside custom components

    ⚠️ Pitfalls

    • Mutable current Property: Although `ref.current is mutable, avoid mutating objects used in rendering
    • No Re-render on Change: Adjusting ref.current doesn’t trigger a re-render; React doesn’t detect changes to the ref
    • Avoid Reading/Writing During Rendering: Refrain from accessing or altering ref.current while rendering, except for its initialization
    • Strict Mode Double Render: In strict mode, React may execute your component twice for side effect detection. This double execution results in the ref object being created twice, though one is discarded
    • Pure Component Behavior: React assumes your component is a pure function. Interacting with a ref during rendering contradicts this presumption

    Read more about useRef on the offical docs

    5. useReducer: Advanced State Logic 📊

    The useReducer is a React Hook that lets you add a reducer to your component, providing a more predictable state management method compared to useState.

    import React, { useReducer } from 'react';
    
    function counterReducer(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(counterReducer, { count: 0 });
    
      return (
        <div>
          <p>Count: {state.count}</p>
          <button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
          <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
        </div>
      );
    }

    Figure: React Counter Component Using useReducer

    • Adding a Reducer to a Component: useReducer allows you to manage your component's state using a reducer function
    • Predictable State Updates: Reducers specify how the state transitions from one state to the next, making state updates more predictable
    • Handling Complex State Logic: It's suitable for managing state logic that's more complex than what useState can handle
    • Avoiding Recreating the Initial State: React saves the initial state once and ignores it on subsequent renders. This is useful for values that are expensive to compute
    • Dispatching Actions: Actions describe user interactions or events that trigger state changes. By convention, actions are objects with a type property
    • Batching State Updates: React batches state updates, ensuring that the screen updates after all event handlers have run

    ⚠️ Pitfalls

    • State Mutations: State in reducers should be treated as immutable. Avoid mutating state directly; always return new state objects
    • Incomplete State Updates: Ensure that every branch in your reducer returns all parts of the state
    • Unexpected State Values: If your state unexpectedly becomes undefined, it's likely due to missing state in one of the reducer cases or a mismatched action type
    • Too Many Re-renders: This error typically indicates that you're unconditionally dispatching an action during render, leading to an infinite loop
    • Impure Reducers: Reducers should be pure functions. Impurities can lead to unexpected behaviors, especially in strict mode where reducers might be called twice

    Read more about useReducer on the offical docs

We open source. Powered by GitHub