The Road to React

website·Indexed 29 days ago

https://the-road-to-react-online.vercel.app

A comprehensive guide to learning React, covering fundamentals such as component declaration, composition, and state lifting, as well as advanced topics like asynchronous data fetching, paginated fetch, and performance optimization. The documentation includes practical sections on styling with CSS Modules and Styled Components, testing with React Testing Library, TypeScript integration, and deployment processes using Firebase.

Tokens
27.3K
Snippets
131
Records
171
Agent score
74%

What's inside The Road to React

  1. Understand React component declaration vs instantiation

    In React, there is a fundamental distinction between declaring a component and instantiating it. A component declaration serves as a blueprint that defines the structure and behavior of the UI. An instantiation occurs when that component is used as an element within JSX. A single component declaration can be used to create multiple independent instances of that component throughout the application.
    // Component Declaration: The blueprint
    function List() {
      return <ul><li>Item 1</li></ul>;
    }
    
    function App() {
      return (
        <div>
          {/* Component Instantiation: Creating multiple instances from one declaration */}
          <List />
          <List />
        </div>
      );
    }
  2. Understand the purpose and capabilities of Custom Hooks

    Custom hooks are JavaScript functions that utilize built-in React hooks (like useState and useEffect) to encapsulate and reuse stateful logic across multiple function components.

    Key capabilities include:

    • Abstraction: Encapsulate non-trivial implementation details away from the UI component.
    • Composition: A custom hook can be a composition of multiple other hooks.
    • State & Side Effects: They can manage their own state and perform side effects (e.g., data fetching, localStorage synchronization).
    • Parameterization: They can accept arguments to customize their behavior for different components.
  3. Understand JSX transpilation and file extensions

    Browsers cannot read JSX directly. It must be transpiled into regular JavaScript (specifically React.createElement() calls) using tools like Babel or Vite. While some build tools allow JSX inside .js files, using the .jsx extension is recommended to explicitly signal that the file contains JSX markup.
    // JSX Source
    const myElement = <h1 className="title">Hello React</h1>;
    
    // Transpiled JavaScript
    const myElement = React.createElement('h1', { className: 'title' }, 'Hello React');
  4. Understand Declarative vs Imperative programming in React

    React primarily uses a declarative approach, where developers describe what the UI should look like based on state, and React handles the how (DOM manipulation). Imperative programming, by contrast, involves providing explicit step-by-step instructions to perform a task. While declarative code is preferred for readability and maintainability, imperative access is necessary for specific tasks such as measuring element dimensions, managing focus, orchestrating complex animations, or integrating third-party imperative libraries like D3.
  5. Understand React's role in Single-Page Applications (SPA)

    React is a JavaScript library used to build Single-Page Applications (SPAs). Unlike traditional server-rendered websites where the server returns a new HTML file for every page transition, an SPA delivers a minimal HTML file and a JavaScript bundle to the client. React then takes over in the browser, dynamically rendering content and handling user interactions without requiring additional server requests for new pages. The core architectural unit in React is the 'component,' which encapsulates visual and functional logic using HTML, CSS, and JavaScript, allowing developers to build complex applications by composing a hierarchy of these components.
  6. Implement server-side search with React useEffect

    To transition from client-side filtering to server-side searching, use a useEffect hook that triggers a data fetch whenever the search term changes. This ensures the application retrieves fresh, filtered data from the remote API rather than filtering a local subset of data. To prevent unnecessary API calls, include a guard clause to return early if the search term is empty or null.
    const App = () => {
      // ... state for searchTerm and stories ...
    
      React.useEffect(() => {
        // Prevent requests if searchTerm is null, empty string, or undefined
        if (!searchTerm) return;
    
        dispatchStories({ type: 'STORIES_FETCH_INIT' });
    
        fetch(`${API_ENDPOINT}${searchTerm}`)
          .then((response) => response.json())
          .then((result) => {
            dispatchStories({
              type: 'STORIES_FETCH_SUCCESS',
              payload: result.hits,
            });
          })
          .catch(() =>
            dispatchStories({ type: 'STORIES_FETCH_FAILURE' })
          );
      }, [searchTerm]); // Dependency array ensures re-fetching on searchTerm change
    
      return (
        <div>
          {stories.isLoading ? (
            <p>Loading ...</p>
          ) : (
            <List list={stories.data} onRemoveItem={handleRemoveStory} />
          )}
        </div>
      );
    };
  7. Create a basic React function component

    A React function component is a JavaScript function that returns JSX (HTML-like code). To be recognized as a component by React, the function name must be written in PascalCase (starting with a capital letter). Function components are the modern standard for building React applications.
    function App() {
      return (
        <div>
          <h1>Hello React</h1>
        </div>
      );
    }
    
    export default App;
  8. Test API error handling (unhappy path) in React components

    To test how a component handles API failures, mock the axios request to return a rejected promise. Wrap the waitFor call in a try/catch block to assert that the error UI (e.g., an error message) is displayed correctly.
    it('fails fetching data', async () => {
      const promise = Promise.reject();
      axios.get.mockImplementationOnce(() => promise);
    
      render(<App />);
    
      expect(screen.getByText(/Loading/)).toBeInTheDocument();
    
      try {
        await waitFor(async () => await promise);
      } catch (error) {
        expect(screen.queryByText(/Loading/)).toBeNull();
        expect(screen.queryByText(/went wrong/)).toBeInTheDocument();
      }
    });
  9. Type useRef for DOM elements

    The useRef hook does not automatically infer the type of the DOM element it attaches to. You must provide a generic type (e.g., <HTMLInputElement>) and initialize it with null to ensure the current property is correctly typed.
    const inputRef = React.useRef<HTMLInputElement>(null);
    
    React.useEffect(() => {
      if (inputRef.current) {
        inputRef.current.focus();
      }
    }, []);
  10. Unit test JavaScript functions in React

    To unit test a function (such as a reducer) located in a component file, you must use named exports for that function. In the test file, import the function and provide mock data to verify that the function returns the expected output based on specific inputs.
    // src/App.jsx
    export default App;
    export { storiesReducer }; // Named export for testing
    
    // src/App.test.jsx
    import { describe, it, expect } from 'vitest';
    import { storiesReducer } from './App';
    
    const storyOne = { title: 'React', objectID: 0 };
    const stories = [storyOne];
    
    describe('storiesReducer', () => {
      it('removes a story from all stories', () => {
        // Test logic here: call storiesReducer with state and action
      });
    });
  11. Enable SVG support in Vite using vite-plugin-svgr

    Vite does not support importing SVGs as React components by default. To enable this functionality, install the vite-plugin-svgr plugin and add it to the Vite configuration plugins array.
    npm install vite-plugin-svgr --save-dev
    // vite.config.js
    import { defineConfig } from 'vite';
    import react from '@vitejs/plugin-react';
    import svgr from 'vite-plugin-svgr';
    
    export default defineConfig({
      plugins: [react(), svgr()],
    });
  12. Implement a toggleable reverse sort in a React list

    To implement a sort feature that toggles between ascending and descending order when a sort button is clicked twice, maintain a state object containing both the sortKey and a boolean isReverse flag. The logic should check if the clicked sortKey matches the current active key; if it does and the list is not already reversed, toggle the isReverse state to true. Finally, apply the sorting function and conditionally call the JavaScript .reverse() method on the resulting array based on the isReverse state.
    const List = ({ list, onRemoveItem }) => {
      const [sort, setSort] = React.useState({
        sortKey: 'NONE',
        isReverse: false,
      });
    
      const handleSort = (sortKey) => {
        // Toggle reverse if the same key is clicked and it's not already reversed
        const isReverse = sort.sortKey === sortKey && !sort.isReverse;
        setSort({ sortKey, isReverse });
      };
    
      const sortFunction = SORTS[sort.sortKey];
      const sortedList = sort.isReverse
        ? sortFunction(list).reverse()
        : sortFunction(list);
    
      return (
        // Render sortedList here
      );
    };