css - React-Router 和 Material-UI : Applying custom themes depending on route

标签 css reactjs react-router material-ui react-router-dom

我刚开始使用 Material-UI。我知道我可以在组件中使用 createStyles 来设置其样式,并且我还可以使用 createMuiTheme 创建全局主题。我想做的是以 createMuiTheme 方式创建一个主题,并包含许多不同的主色和辅助色组合。

我正在制作一个显示 NHL 球队统计数据的网络应用程序。我正在动态创建一个组件,该组件根据 React-Router 和页面 URL 显示团队统计信息。例如,如果用户访问 /rangers,则页面显示纽约游骑兵队统计数据,如果用户访问 /bruins,则页面显示波士顿棕熊队统计数据,等等...

我实现这一点的方法是使用React-Router的 useLocation功能。当用户导航到 /rangers 时,我使用 useLocation 从 URL 中获取 rangers 并将团队名称放入 GET 请求中,以便 Rangers请求并显示统计信息。

我想做的是创建一个 Material-UI 主题,以根据所属团队动态设置页面上的主要颜色和次要颜色。例如,当用户位于 /rangers (流浪者队颜色)时,我想将主要颜色设置为蓝色,次要颜色设置为红色。如果用户要导航到 /bruins 那么我想将主要颜色和次要颜色设置为 Bruins 团队颜色(黑色和金色)。

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

有没有一种方法可以根据 React-Router 所在的页面在 Material-UI 中动态设置主题颜色,即导航到 /rangers > 设置 Rangers 颜色并导航到 /bruins 在主题中设置 Bruins 颜色?我想以与执行 GET 请求类似的方式使用 useLocation 来实现此目的。

我有 31 个不同的团队/页面,因此动态执行此操作比手动创建具有不同样式的 31 个不同组件要高效得多。

最佳答案

您可以创建一种修改主题的方法。在这种情况下,我们需要了解如何在组件树中渲染组件。不过,我做了一个简单的操作示例,您可以将其作为您实现的基础。

Edit Button

从技术上讲,您需要使用 Context Api 创建自定义主题提供程序,以便可以从应用程序中的任何位置访问它。这样我们就可以在任何组件中修改主题。

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>
  );
}

然后提供一个通用的更改入口点。

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

最后,我们可以在 React 树顶部的组件上以这种方式使用它。

  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]);

希望对您有所帮助。

关于css - React-Router 和 Material-UI : Applying custom themes depending on route,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61600091/

相关文章:

html - 为什么 `display: none` 不加载背景图片?

javascript - Bootstrap Navbar 固定顶部 OverFlow 水平设置固定高度使内容可滚动以避免切换按钮

javascript - React 中的切换功能

javascript - React 如何在调用 onSubmit 时绑定(bind)到组件

javascript - 您不能对同一动态路径 Nextjs 使用不同的 slug 名称

css - 有没有办法通过css缩放GtkImage显示?

css - Aurelia,作用域 css

reactjs - Apollo GraphQL 本地和全局错误处理

javascript - ReactJS:具有多个 View 的侧边栏

javascript - 添加 CSS @keyframes 动画以在 React 应用程序中进行状态更改