React-Router 和 Material-UI:根据路由应用自定义主题
Posted
技术标签:
【中文标题】React-Router 和 Material-UI:根据路由应用自定义主题【英文标题】:React-Router and Material-UI: Applying custom themes depending on route 【发布时间】:2020-08-19 08:14:32 【问题描述】:我刚开始使用Material-UI
。我知道我可以在一个组件中使用createStyles
来设置它的样式,并且我也可以使用createMuiTheme
来创建一个全局主题。我想做的是以createMuiTheme
的方式创建一个主题,并包含许多不同的原色和二次色组合。
我正在制作一个显示 NHL 球队统计数据的网络应用。我正在动态创建一个组件,该组件根据React-Router
和页面 URL 显示团队统计信息。例如,如果用户转到/rangers
,则页面显示纽约游骑兵队的统计数据,如果用户转到/bruins
,则页面显示波士顿棕熊队的统计数据等...
我实现这一点的方法是使用 React-Router's
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 颜色?我想为此使用useLocation
,其方式与我执行 GET 请求的方式类似。
我有 31 个不同的团队/页面,因此动态执行此操作比手动创建具有不同样式的 31 个不同组件更有效。
【问题讨论】:
【参考方案1】:您可以创建一种修改主题的方法。在这种情况下,我们需要了解如何在组件树中渲染组件。但是,我做了一个简单的操作示例,您可以将其作为实现的基础。
从技术上讲,您需要使用 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]);
希望对你有帮助。
【讨论】:
非常好的答案! 感谢您的详细回复。这绝对给了我一个很好的起点。以上是关于React-Router 和 Material-UI:根据路由应用自定义主题的主要内容,如果未能解决你的问题,请参考以下文章
如何用 redux 和 react-router 组织状态?