我从样式组件设置了主题提供程序,然后创建了一个门户,并且我的门户中的元素无法访问提供程序
这是我的提供者:
<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>
);
}, [...]);
如何在我的门户组件中访问主题提供程序值?
// ./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>
)
}
// ./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 }
}
// ./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;
💬 我使用 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>;
}
// 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} />
}
// 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>
)