如何在react-styleguidist的Wrapper组件中访问react上下文?

时间:2020-07-18 01:26:40

标签: javascript reactjs react-context react-styleguidist

我想要什么:

我正在尝试为正在处理的react-styleguidist项目添加动态主题选项。遵循this unfinished and closed pr中提出的想法,我添加了一个自定义ThemeSwitcher组件,这是一个在目录侧边栏中呈现的选择菜单。选择一个选项将更新brand上下文,该上下文使用样式组件的BrandProvider渲染相应的主题。它的功能应类似于已关闭的pr:https://fancy-sg.surge.sh/中包含的演示。

什么不起作用:

我无法访问ThemedWrapperStyleguideWrapper中提供并更新的ThemeSwitcher中的相同上下文。在React Components控制台中检查树,看起来react-styleguidist可能会渲染ReactExample的{​​{1}} 外部,这意味着它将丢失该组件中提供者的上下文

假设由于上下文位于StyleguideRenderer之外而未在ThemedWrapper中进行更新,我是正确的,我有两个高级想法(但无法弄清楚如何做)是:

  1. 在react-styleguidist库中找到同时是StyleGuideRenderer StyleGuideRenderer的祖先的正确组件,并在其中添加ReactExample,以便{{ 1}}现在具有上下文访问权限
  2. 我尚未发现的其他一些上下文配置,将允许两个组件在不使用提供者作为祖先的情况下使用同一上下文(这可能吗?)

我所拥有的:

这是我正在使用的相关代码的精简版本。

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

0 个答案:

没有答案