← Back to Main Page

Module 3: Build Sprint 2

Your Second Ticket

Now that you've completed your first ticket, it's time to tackle more complex features and advance your understanding of the project.

Your Second Ticket

State Management

As your application grows, proper state management becomes crucial. Learn about different state management approaches in React applications.

// Example using React Context API for global state
import React, { createContext, useContext, useReducer } from 'react';

// Initial state
const initialState = {
  user: null,
  isAuthenticated: false,
  theme: 'light'
};

// Create context
const AppContext = createContext();

// Reducer function
function reducer(state, action) {
  switch (action.type) {
    case 'LOGIN':
      return {
        ...state,
        user: action.payload,
        isAuthenticated: true
      };
    case 'LOGOUT':
      return {
        ...state,
        user: null,
        isAuthenticated: false
      };
    case 'TOGGLE_THEME':
      return {
        ...state,
        theme: state.theme === 'light' ? 'dark' : 'light'
      };
    default:
      return state;
  }
}

// Context provider component
export function AppProvider({ children }) {
  const [state, dispatch] = useReducer(reducer, initialState);
  
  return (
    <AppContext.Provider value={{ state, dispatch }}>
      {children}
    </AppContext.Provider>
  );
}

// Custom hook to use the context
export function useAppContext() {
  return useContext(AppContext);
}

Testing Your Components

Learn how to write effective tests for your React components to ensure they work as expected.

// Example of testing a React component with Jest and React Testing Library
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import Counter from './Counter';

describe('Counter Component', () => {
  test('renders with initial count of 0', () => {
    render(<Counter />);
    
    const countElement = screen.getByText(/count: 0/i);
    expect(countElement).toBeInTheDocument();
  });
  
  test('increments count when increment button is clicked', () => {
    render(<Counter />);
    
    const incrementButton = screen.getByRole('button', { name: /increment/i });
    fireEvent.click(incrementButton);
    
    const countElement = screen.getByText(/count: 1/i);
    expect(countElement).toBeInTheDocument();
  });
  
  test('decrements count when decrement button is clicked', () => {
    render(<Counter />);
    
    const decrementButton = screen.getByRole('button', { name: /decrement/i });
    fireEvent.click(decrementButton);
    
    const countElement = screen.getByText(/count: -1/i);
    expect(countElement).toBeInTheDocument();
  });
});

Improving Performance

As you add more features to your application, optimizing performance becomes important. Learn strategies to improve React app performance.

Performance Optimization Tips

Here are some key techniques to improve React application performance:

  • Use React.memo for component memoization
  • Implement useCallback for memoizing functions
  • Use useMemo for expensive calculations
  • Virtualize long lists with react-window or react-virtualized
  • Implement code-splitting with React.lazy and Suspense
  • Use proper keys for items in lists
  • Avoid unnecessary re-renders
  • Consider using the production build for deployment
// Example of using React.memo and useCallback
import React, { useState, useCallback } from 'react';

// Memoized child component
const ExpensiveComponent = React.memo(({ onClick, name }) => {
  console.log(`ExpensiveComponent ${name} rendered`);
  return (
    <button onClick={onClick}>
      Click {name}
    </button>
  );
});

function App() {
  const [count1, setCount1] = useState(0);
  const [count2, setCount2] = useState(0);
  
  // Memoize callbacks to prevent recreation on every render
  const incrementCount1 = useCallback(() => {
    setCount1(c => c + 1);
  }, []);
  
  const incrementCount2 = useCallback(() => {
    setCount2(c => c + 1);
  }, []);
  
  return (
    <div>
      <div>Count 1: {count1}</div>
      <div>Count 2: {count2}</div>
      <ExpensiveComponent onClick={incrementCount1} name="Button 1" />
      <ExpensiveComponent onClick={incrementCount2} name="Button 2" />
    </div>
  );
}