← All tasksReact · Middle

Theme with Context

Write a ThemeProvider and a useTheme hook. The provider stores the theme - "light" (default) or "dark" - and makes it available to every component inside. useTheme() returns { theme, toggleTheme }, where toggleTheme switches the theme.

All components under one provider see the same theme. Calling useTheme outside the provider must throw an error whose message contains ThemeProvider.

Tests (3)

  1. function Probe() {
      const { theme, toggleTheme } = useTheme();
      return <button onClick={toggleTheme}>{theme}</button>;
    }
    render(<ThemeProvider><Probe /></ThemeProvider>);
    expect(screen.getByRole('button').textContent).toBe('light');
    fireEvent.click(screen.getByRole('button'));
    expect(screen.getByRole('button').textContent).toBe('dark');
    fireEvent.click(screen.getByRole('button'));
    expect(screen.getByRole('button').textContent).toBe('light');
  2. function Probe() {
      const { theme, toggleTheme } = useTheme();
      return <button onClick={toggleTheme}>{theme}</button>;
    }
    render(<ThemeProvider><Probe /><Probe /></ThemeProvider>);
    fireEvent.click(screen.getAllByRole('button')[0]);
    expect(screen.getAllByRole('button').map((b) => b.textContent)).toEqual(['dark', 'dark']);
  3. expect(() => renderHook(() => useTheme())).toThrow('ThemeProvider');