如何在 React 中将样式组件的 themeProvider 访问到 Portal 中?

问题描述 投票:0回答:1

我从样式组件设置了主题提供程序,然后创建了一个门户,并且我的门户中的元素无法访问提供程序

这是我的提供者:

<ConfigProvider>
  <ThemeProvider theme={myTheme}> //<-- provider from styled-components
    <App />
  </ThemeProvider>
</ConfigProvider>

这就是我创建门户的方式:

export const SetSelector = ()=>{
  const OptionsModal = useMemo(() => {
      return (
          <Wrapper $theme={configState.theme}>
            <Modal $theme={configState.theme}>
              // more components here, like buttons
            </Modal>
          </Wrapper>
      );
    }, [ . . . ]);
  
    return (
      <ListSelectorWrapper>
        {displayOptions && createPortal(OptionsModal, document.body)}
      </ListSelectorWrapper>
    );
  };
}

我的模态组件无法从样式组件访问主题提供程序,我收到此错误:

Uncaught TypeError: Cannot read properties of undefined (reading '300')
,它来自我的按钮的属性:

background: ${props=>props.$variant==="flat"?"transparent":props.$theme==="dark"?props.theme.gray[300]:props.theme.gray[600]};

另外,我尝试将我的门户包装在提供商中,但不起作用,我遇到了同样的错误

const OptionsModal = useMemo(() => {
    return (
      <ThemeProvider theme={myTheme}>
        <WrapperOverlay $theme={configState.theme}>
          <Modal $theme={configState.theme}>
             // more components here, like buttons
          </Modal>
        </WrapperOverlay>
      </ThemeProvider>
    );
  }, [...]);

如何在我的门户组件中访问主题提供程序值?

reactjs styled-components react-context react-portal
1个回答
0
投票

我使用样式组件的方式。

  1. 创建主题上下文

// ./context/ThemeContext.jsx

import { useState, createContext } from 'react'

export const ThemeContext = createContext()

export const ThemeProvider = ({ children }) => {
    const [theme, setTheme] = useState('light')

    return (
        <ThemeContext.Provider value={{ theme, setTheme }}>
            {children}
        </ThemeContext.Provider>
    )
}
  1. 创建自定义挂钩:“useTheme”。

// ./hooks/useTheme.jsx

import { useContext } from "react"
import { ThemeContext } from "../context/ThemeContext"

export function useTheme() {
    const { theme, setTheme } = useContext(ThemeContext);

    const toggleTheme = () => {
        setTheme(t => t === 'light' ? 'dark' : 'light')
    }

    return { theme, toggleTheme }
}
  1. 创建主题按钮。

// ./components/ThemeButton.jsx

import { useTheme } from '../hooks/useTheme';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faLightbulb, faMoon } from '@fortawesome/free-regular-svg-icons';

// create the ButtonWrapper component
// retrieve data from the mode property
// change color when the darkmode is active

const ButtonWrapper = styled.button`
    color: ${(props) => props.mode === 'dark' && 'white'};
    background-color: transparent;
    border: none;
`

const ThemeButton = () => {
    // use custom hook
    const { theme, toggleTheme } = useTheme()

    return (
        // add "mode" props  to the component
        // that will have the value "theme"

        <ButtonWrapper
            type="button"
            mode={theme}
            onClick={() => toggleTheme()}
        >
            {theme === 'light' ? (
                <FontAwesomeIcon icon={faMoon} />
            ) : (
                <FontAwesomeIcon icon={faLightbulb} />
            )}
        </ButtonWrapper>
    );
}

export default ThemeButton;
  1. 创建 StyledProvider

💬 我使用 Styled-Components 中的 ThemeProvider,就像我将样式变量与 SASS 一起使用一样。

// ./context/StyledContext.jsx

import { ThemeProvider } from 'styled-components';

const styled = {
    colors: {
        black: "black",
        white: "white",
    },
}

export const StyledProvider = ({ children }) => {
    return <ThemeProvider theme={styled}>{children}</ThemeProvider>;
}

  1. 创建全局样式

// GlobalStyle.jsx

import { createGlobalStyle } from "styled-components";
import { useTheme } from "./hooks/useTheme";

// {props => props.mode} to retrieve data from the mode property
// {props => props.theme} to retrieve data from StyledProvider

const GlobalStyleComponent = createGlobalStyle`
    body {
        background-color: ${props => props.mode === "dark" ? props.theme.colors.black : props.theme.colors.white };
        transition-duration: 200ms;
    }
`;

export const GlobalStyle = () => {
    const { theme } = useTheme()
    return <GlobalStyleComponent mode={theme} />
}
  1. 使用 StyledProvider 和 ThemeProvider 包装您的应用程序。

// index.jsx
import { StrictMode } from "react";
import ReactDOM from "react-dom/client";
import { StyledProvider } from './context/StyledContext';
import { ThemeProvider } from './context/ThemeContext';
import { GlobalStyle } from './GlobalStyle';

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
    <StrictMode>
        <StyledProvider>
          <ThemeProvider>
              <GlobalStyle/>
             <App>
          </ThemeProvider>
        </StyledProvider>
    </StrictMode>
)
© www.soinside.com 2019 - 2024. All rights reserved.