Utilizing Different Themes Based on Route with React-Router and Material-UI

I'm currently learning how to utilize the Material-UI library. As I explore its capabilities, I have discovered that I can use createStyles within a component to style it, and I can also leverage createMuiTheme to establish a global theme. My goal is to create a theme using createMuiTheme that incorporates various primary and secondary color combinations.

My project involves developing a web application that showcases NHL team statistics. I am dynamically generating a component to display team statistics based on React-Router and the URL of the page. For instance, visiting /rangers will show the statistics for the New York Rangers, and visiting /bruins will display the Boston Bruins' stats.

To achieve this, I am using React-Router's useLocation function. By extracting the team name from the URL using useLocation when the user navigates to a specific team page, I can make a GET request for that team's statistics to be retrieved and displayed.

My aim is to create a Material-UI theme that dynamically adjusts the primary and secondary colors on the page based on the selected team. For example, when on the /rangers page, I want the primary color to be blue and the secondary color to be red (representing the Rangers team colors). If the user then navigates to /bruins, I want the primary and secondary colors to switch to the Bruins' team colors (black and gold).

const Theme = createMuiTheme({
    palette: {
        primary: {
          // Setting primary color to Rangers blue when on '/rangers'
          rangers: '#0038a8',
          // Setting primary color to Bruins gold when on '/bruins'
          bruins: '#fcb514'
        },
        secondary: {
          // Setting secondary color to Rangers red when on '/rangers'
          rangers: '#ce1126',
          // Setting secondary color to Bruins black when on '/bruins'
          bruins: '#111'
        }
    });

Is there a way to dynamically adjust theme colors in Material-UI based on the current React-Router page, such as changing the theme colors to reflect the team colors when navigating to a specific team's page like /rangers or /bruins? I would like to implement this using useLocation in a similar manner to how I handle the GET request.

With a total of 31 different teams/pages to consider, dynamically managing theme colors is much more efficient than creating separate components with different styles for each team.

Answer №1

If you're looking to customize your theme, understanding how components are rendered in the component tree is crucial. However, I have put together a simple example to get you started on modifying your theme.

https://codesandbox.io/s/material-demo-ilqxp

To achieve this, you'll need to create a customized theme provider using the Context API so that it can be accessed from anywhere in your application. This will allow you to modify the theme in any component.

export function ThemeProvider(props) {
  const { children } = props;

  const [themeOptions, dispatch] = React.useReducer((state, action) => {
    switch (action.type) {
      case "CHANGE":
        return {
          ...state,
          colors: action.payload.colors || "DEFAULT"
        };
      default:
        throw new Error(`Unrecognized type ${action.type}`);
    }
  }, themeInitialOptions);

  const { colors } = themeOptions;
  const theme = React.useMemo(() => {
    let palette;

    switch (colors) {
      case "RANGERS":
        palette = {
          primary: { main: "#0038a8" },
          secondary: { main: "#ce1126" }
        };
        break;
      case "BRUINS":
        palette = {
          primary: { main: "#fcb514" },
          secondary: { main: "#111" }
        };
        break;
      default:
        palette = {
          primary: { main: "#673ab7" },
          secondary: { main: "#111" }
        };
        break;
    }

    const nextTheme = createMuiTheme({ palette });
    return nextTheme;
  }, [colors]);

  return (
    <MuiThemeProvider theme={theme}>
      <DispatchContext.Provider value={dispatch}>
        {children}
      </DispatchContext.Provider>
    </MuiThemeProvider>
  );
}

Once you have set up the theme provider, you can create a common entry point for making changes.

export function useChangeTheme() {
  const dispatch = React.useContext(DispatchContext);
  return React.useCallback(
    themeOptions => dispatch({ type: "CHANGE", payload: themeOptions }),
    [dispatch]
  );
}

Lastly, you can utilize this functionality in the top component of your React tree by:

  const changeTheme = useChangeTheme();
  const location = useLocation();

  React.useEffect(() => {
    let path = location && location.pathname.split("/");
    let team = path && path[1];
    changeTheme({ colors: team.toUpperCase() });
  }, [changeTheme, location]);

Hopefully, this guide serves as a helpful starting point for you.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is there a way to prevent a page from rendering until the necessary data is retrieved?

I am facing an issue where my page is attempting to render before the data is available. I have used async/await in my code, but I keep getting an error saying that the data is undefined. Interestingly, when I comment out the page elements and check the Re ...

The functionality of WrapAll is not functioning properly in React JS

$('p').wrapAll($('<div class="wrapper"></div>')); .wrapper { background: #EEE; margin: 10px; padding: 5px; border: 1px solid black; } <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery. ...

Guide to organizing documents using an interface structure

I currently have an interface that outlines the structure of my documents within a specific collection: interface IGameDoc { playerTurn: string; gameState: { rowOne: [string, string, string] rowTwo: [string, string, string] ...

Understanding how to utilize environment variables in React.js can drastically improve

One of the key components in my project is using an environment variable like this: process.env.GOOGLE_MAPS_API This variable holds a Google API key which is crucial for rendering maps. However, I'm facing an issue with the following code snippet: ...

I am facing an issue with my useFetch hook causing excessive re-renders

I'm currently working on abstracting my fetch function into a custom hook for my Expo React Native application. The goal is to enable the fetch function to handle POST requests. Initially, I attempted to utilize and modify the useHook() effect availab ...

transferring data between react components

I am currently working on breaking down code into smaller components, starting with the snippet below from Rows.jsx. I am struggling to grasp how props are passed between parent and child components. Despite reading several guides and articles, I remain un ...

Expanding a feature that modifies the CSS properties of every input element

Creating a text tracking (letter-spacing) demonstration where range sliders are used to update CSS properties. I'm looking to improve the functionality so that the labels also update dynamically, without repeating output2.textContent = this.value;. An ...

Storing the value of e.currentTarget in a TypeScript variable with a fixed data type

Within my interface, MyObject.type is designated as a type of (constant): 'orange' | 'apple'. However, when attempting to execute: MyObject.type = e.currentTarget.value in the onChange method, an error arises since it could potentially ...

CSS and jQuery UI URLs are not resolving properly in MVC framework after deployment

Basically, the issue is that the url for an image in jquery-ui.css file does not resolve once the site is deployed. The website is deployed under the default web site in IIS7, causing the browser console to look for the image in a different location than e ...

In the case that the prop is empty or undefined, display an error message before rendering the full component

I am working on an ImageBlock component, which has several props like url, alt, caption, and optionally quality with a default value of 75. The essential prop here is the url. I need a quick way to immediately display an AlertError if the url is not provi ...

Invoke a function within the redux reducer

The code within my reducer is structured as follows: import {ADD_FILTER, REMOVE_FILTER} from "../../../../actions/types"; const removeFilter = (state, name) => { return state.filter(f => f.name !== name); }; export default function addRemoveFi ...

Is it possible to monitor nested object modifications within React Context?

Scenario: const initState = { count: 1; increase() { ++this.count; } } const ContextApp = React.createContext({ myState: initState }); Within the React component class MyElement extends Component { static contextType = ContextApp; compon ...

Is it possible to amalgamate CSS declarations together?

You have the ability to combine CSS selectors by using a comma, like in this example: .one, .two { color: #F00; } <div class="one">One</div> <div class="two">Two</div> Using this method produces the same outcome as specifying ...

Create a single declaration in which you can assign values to multiple const variables

As a newcomer to react/JS, I have a question that may seem basic: I need multiple variables that are determined by a system variable. These variables should remain constant for each instance. Currently, my approach is functional but it feels incorrect to ...

Using jQuery to remove the 'active class' when the mouse is not hovering

I recently came across this amazing jQuery plugin for creating slide-out and drawer effects: However, I encountered a problem. I want to automatically close the active 'drawer' when the mouse is not hovering over any element. The jQuery plugin c ...

Issue with deprecated TypeORM connection and isConnected functions

import { Module } from '@nestjs/common'; import { Connection } from '../../node_modules/typeorm/connection/Connection'; import { TypeOrmModule } from '@nestjs/typeorm'; @Module({ imports: [TypeOrmModule.forRoot()], exports ...

"Efficiently manage search suggestions and arrange outcomes for autofill text input utilizing jQuery

Is there a way to eliminate the message and structure the results in a sleek dropdown using CSS without relying on Bootstrap or pre-made CSS files? http://jsfiddle.net/SCuas/96/ var aCleanData = ['test','test1','abcd',' ...

Capable of generating accounts using Postman, experiencing difficulties with creating accounts from React

Currently, I am working on a project that utilizes a React/Spring Boot/MYSQL stack and I have encountered an error message stating "POST 415: SyntaxError: Unexpected end of input at line 67". Line 67 is as follows: }).then(res => res.json()) This sect ...

Issue alert before running tests on component that includes a Material UI Tooltip

This is a follow-up regarding an issue on the Material-UI GitHub page. You can find more information here. Within my Registration component, there is a button that is initially disabled and should only be enabled after accepting terms and conditions by ch ...

Some of the items in the dropdown menu are not fully displayed

I'm currently working on a drop-down menu, but I'm facing an issue where adding position: absolute; and display: block; is causing the second ul element to not be fully visible. My goal is to have both ul elements visible so that I can proceed to ...