我正在尝试为正在处理的react-styleguidist项目添加动态主题选项。遵循this unfinished and closed pr中提出的想法,我添加了一个自定义ThemeSwitcher
组件,这是一个在目录侧边栏中呈现的选择菜单。选择一个选项将更新brand
上下文,该上下文使用样式组件的BrandProvider
渲染相应的主题。它的功能应类似于已关闭的pr:https://fancy-sg.surge.sh/中包含的演示。
我无法访问ThemedWrapper
和StyleguideWrapper
中提供并更新的ThemeSwitcher
中的相同上下文。在React Components控制台中检查树,看起来react-styleguidist可能会渲染ReactExample
的{{1}} 外部,这意味着它将丢失该组件中提供者的上下文
假设由于上下文位于StyleguideRenderer
之外而未在ThemedWrapper
中进行更新,我是正确的,我有两个高级想法(但无法弄清楚如何做)是:
StyleGuideRenderer
和 StyleGuideRenderer
的祖先的正确组件,并在其中添加ReactExample
,以便{{ 1}}现在具有上下文访问权限这是我正在使用的相关代码的精简版本。
brand-context.js (受Kent C Dodds启发,导出上下文和提供程序
BrandProvider
StyleGuideWrapper.jsx (rsg-components / StyleguideRenderer的副本,添加了ThemeSwitcher组件以从ui切换主题;以ThemedWrapper
的形式在styleguide配置中传递)
import React, { createContext, useState, useContext } from 'react';
const BrandStateContext = createContext();
const BrandSetContext = createContext();
function BrandProvider({ children, theme }) {
const [brand, setBrand] = useState(theme);
return (
<BrandStateContext.Provider value={brand}>
<BrandSetContext.Provider value={(val) => setBrand(val)}>
{children}
</BrandSetContext.Provider>
</BrandStateContext.Provider>
);
}
function useBrandState() {
return useContext(BrandStateContext);
}
function useBrandSet() {
return useContext(BrandSetContext);
}
export { BrandProvider, useBrandState, useBrandSet };
ThemeSwitcher.jsx
StyleGuideRenderer
ThemedWrapper.jsx (作为import React from 'react';
import cx from 'clsx';
import Styled from 'rsg-components/Styled';
import ThemeSwitcher from './ThemeSwitcher';
import { BrandProvider } from './brand-context';
export function StyleGuideRenderer({ children, classes, hasSidebar, toc }) {
return (
<BrandProvider>
<div className={cx(classes.root, hasSidebar && classes.hasSidebar)}>
<main className={classes.content}>
{children}
</main>
{hasSidebar && (
<div className={classes.sidebar} data-testid="sidebar">
<section className={classes.sidebarSection}>
<ThemeSwitcher classes={classes} />
</section>
{toc}
</div>
)}
</div>
</BrandProvider>
);
}
StyleGuideRenderer.propTypes = propTypes;
export default Styled(styles)(StyleGuideRenderer);
传入样式指南配置,并包装每个示例组件以将其提供给样式组件)
import React from 'react';
import Styled from 'rsg-components/Styled';
import { useBrandSet, useBrandState } from './brand-context';
const ThemeSwitcher = ({ classes }) => {
const brand = useBrandState();
const setBrand = useBrandSet();
const onBrandChange = (e) => setBrand(e.target.value);
const brands = ['foo', 'bar'];
return (
<label className={classes.root}>
Brand
<select value={brand} onChange={onBrandChange}>
{brands.map((brand) => (
<option key={brand} value={brand}>{brand}</option>
))}
</select>
</label>
);
};
export default Styled(styles)(ThemeSwitcher);