条件css在react-app

4ioopgfo  于 2023-10-21  发布在  React
关注(0)|答案(8)|浏览(121)

我有默认的css文件和单独的css文件,应适用于(owerride默认)只有当某些条件得到满足。
我使用的是默认import 'file.css'语法的react-app。
什么是最好的方法来决定是否加载或不加载特定的css文件动态?

kgsdhlau

kgsdhlau1#

require方法只在开发中起作用(因为所有的CSS都是在构建时捆绑的),而import方法根本不起作用(使用CRA版本3.3)。
在我们的例子中,我们有多个主题,不能捆绑-所以我们使用React.lazyReact.Suspense解决了这个问题。
我们有ThemeSelector,它有条件地加载正确的css。

import React from 'react';

/**
 * The theme components only imports it's theme CSS-file. These components are lazy
 * loaded, to enable "code splitting" (in order to avoid the themes being bundled together)
 */
const Theme1 = React.lazy(() => import('./Theme1'));
const Theme2 = React.lazy(() => import('./Theme2'));

const ThemeSelector: React.FC = ({ children }) => (
  <>
    {/* Conditionally render theme, based on the current client context */}
    <React.Suspense fallback={() => null}>
      {shouldRenderTheme1 && <Theme1 />}
      {shouldRenderTheme2 && <Theme2 />}
    </React.Suspense>
    {/* Render children immediately! */}
    {children}
  </>
);

export default ThemeSelector;

Theme组件的唯一任务是导入正确的css文件:

import * as React from 'react';

// 👇 Only important line - as this component should be lazy-loaded,
//    to enable code - splitting for this CSS.
import 'theme1.css';

const Theme1: React.FC = () => <></>;

export default Theme1;

ThemeSelector应该将App组件 Package 在src/index.tsx中:

import React from 'react';
import ReactDOM from 'react-dom';
import ThemeSelector from 'themes/ThemeSelector';

ReactDOM.render(
  <ThemeSelector>
    <App />
  </ThemeSelector>,
  document.getElementById('root')
);

据我所知,这迫使每个Theme被拆分成单独的bundle(有效地也拆分了CSS)。
正如在评论中提到的,这个解决方案并没有提供一种简单的运行时切换主题的方法。此解决方案侧重于将主题拆分为单独的捆绑包。
如果您已经将主题拆分为单独的CSS文件,并且希望在运行时交换主题,则可能需要使用ReactHelmetillustrated by @Alexander Ladonin's answer below)来查看解决方案。

zaqlnxep

zaqlnxep2#

您可以使用require('file.css')语法代替。这将允许你把它放在条件句中。
例如

if(someCondition) {
    require('file.css');
}
gwo2fgha

gwo2fgha3#

使用React Helmet。它动态地添加链接,Meta标签等到 * 文档头 *。将其添加到任何渲染方法中。

import {Component} from 'react';
import ReactHelmet from 'react-helmet';

class Example extends Component{
    render(
        <ReactHelmet link={
            [{"rel": "stylesheet", type:"text/css", "href": "/style.css"}]
        }/>);
    }
}

你可以在下一个<ReactHelmet/>渲染中重写它。

hwamh0ep

hwamh0ep4#

我发现一个在生产环境中有效的简单解决方案是使用vercel的styled-jsx。首先,安装styled-jsx:

npm install --save styled-jsx

如果你使用Yarn:

yarn add styled-jsx

现在从你的css文件中创建字符串,例如:

const style1 = `
div {
    display: flex;
    flex-direction: column;
    align-items: center;
}
`
const style2 = `
div {
    display: flex;
    flex-direction: column;
    align-items: center;
}
`

然后在你的React组件中,你可以这样做:

const MyComponent = () => {
  return (
    <div className='my-component'>
      <style jsx>
        {
          conditionA ? style1: style2
        }
      </style>
    </div>
  )
}

简单地将<style jsx>{your_css_string}</style>添加到你想要添加样式的组件中,然后你可以使用不同的字符串来导入不同的css样式来实现条件。

wpx232ag

wpx232ag5#

如果你在这里,你最有可能是试图条件的CSS或SCSS导入,可能是使一些光/暗模式的主题或东西。接受的答案只在挂载时起作用,在第二个css加载后,它们都被加载了,你没有办法卸载它们,或者实际上你有,继续阅读.
使用React lazy和suspense是很棒的,但在这种情况下,我们需要从webpack中帮助我们自己,因为实际上是捆绑东西的人,也可以解包东西,这就是你需要的,基本上是css导入的切换
添加webpack lazyStyleTag
转到您的webpack配置文件并添加以下规则

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        // Probly you already have this rule, add this line
        exclude: /\.lazy\.css$/i,
        use: ["style-loader", "css-loader"],
      },
      // And add this rule
      {
        test: /\.lazy\.css$/i,
        use: [
          { loader: "style-loader", options: { injectType: "lazyStyleTag" } },
          "css-loader",
        ],
      },
    ],
  },
};

现在,将CSS文件的名称更改为lazy命名约定
你可能有这个

styles.css 
// or
styles.min.css

现在会是这样:

styles.lazy.css

然后在一个简单的React上下文中创建你的React主题Provider,这个上下文将 Package 你的App,这样每当上下文状态改变时,它就会加载有条件的CSS。这个上下文状态将在你的应用程序中的任何地方都可用,以及通过一个自定义钩子的setter,我们将从同一个文件导出,看看这个:

import React, {
    useEffect, createContext, useState, useContext,
} from 'react';
import { Nullable } from 'types';

// Import both files here like this:

// Import of CSS file number 1
import LightMode from './theme/styles.lazy.css';
// Import of CSS file number 2
import DarkMode from './theme/styles.lazy.css';

interface IContext {
    theme: Nullable<string>
    toggleTheme: () => void
}

const Context = createContext<IContext>({
    theme: null,
    toggleTheme: () => { },
});

// Your Provider component that returns the Context.Provider
// Let's also play with the sessionStorage, so this state doesn't
// brake with browser refresh or logouts
const ThemeProvider: React.FC = ({ children }) => {
    // Im initialazing here the state with any existing value in the 
    //sessionStorage, or not...
    const [theme, setTheme] = useState<Nullable<string>>(sessionStorage.getItem('themeMode') || 'dark');

    // this setter Fn we can pass down to anywhere
    const toggleTheme = () => {
        const newThemeValue = theme === 'dark' ? 'light' : 'dark';
        setTheme(newThemeValue);
        sessionStorage.setItem('themeMode', newThemeValue);
    };

    // Now the magic, this lazy css files you can use or unuse
    // This is exactly what you need, import the CSS but also unimport
    // the one you had imported before. An actual toggle of import in a 
    // dynamic way.. brought to you by webpack
    useEffect(() => {
        if (theme === 'light') {
            DarkMode.unuse();
            LightMode.use();
        } else if (theme == 'dark') {
            LightMode.unuse();
            DarkMode.use();
        }
    }, [theme]);

    return (
        <Context.Provider value={{ theme, toggleTheme }}>
            {children}
        </Context.Provider>
    );
};

export default ThemeProvider;
// This useTheme hook will give you the context anywhere to set the state of // theme and this will toggle the styles imported
export const useTheme = () => useContext(Context);

请记住将此状态放在sessionStorage上(如本例所示),以便用户在每次返回或刷新页面时都可以使用此状态
别忘了用提供商 Package 这个该死的应用程序:

import ThemeProvider from './ThemeProvider'

const App = () => {

   return (
      <ThemeProvider>
        <App />
      </ThemeProvider>

   )
}

现在只需使用很酷的useTheme钩子来切换应用程序的CSS导入

import { useTheme } from './yourContextFile';

// inside your component
const AnyComponentDownTheTree = () => {

   const { theme, toggleTheme } = useTheme()

   // use the toggleTheme function to toggle and the theme actual value 
   // for your components, you might need disable something or set active a 
   // switch, etc, etc 

}
mum43rcc

mum43rcc6#

我在一些教程中测试了一些可用的替代方法,对我来说最好的方法是只使用css中的类。
我在使用时遇到的一个问题是,

要求:在某些情况下没有覆盖
import:加载css产生的延迟

对我来说最好的方法就是把一个类切换

.default-sidebar {
    --side-text-icon:rgba(255,255,255,.9) !important;
    --side-text-section: rgb(255,255,255,.8) !important;
    --side-separator-section:#ff944d !important;
}

.dark-sidebar {
    --side-text-icon:rgba(255,255,255,.9) !important;
    --side-text-section: rgb(255,255,255,.8) !important;
    --side-separator-section:#262626 !important;
}

'

<div className={`root-sidebar ${condition?'default-sidebar':'dark-sidebar'}`}></div>
vawmfj5a

vawmfj5a7#

我通过添加一个有条件呈现的兄弟div,然后利用css selector "+"来定位条件内容,解决了这个问题。下面是一个示例:

# Layout.js

import React, { useState } from "react"
import "./main.css"

function Layout() {
  const [condition, setCondition] = useState(false);

  const toggleCondition = () => setCondition(!condition);

  return (
    <div>
      {condition && <div id="condition-is-true"></div>}
      <div className="content">
         <button onClick={toggleCondition}>Click me</button>
         <div id="conditionally-style-me">This is the content</div>
      </div>
  );
}

export default Layout;
# main.css

#condition-is-true + .content #conditionally-style-me {
   color: red;
}

.content #conditionally-style-me {
   color: black;
}

现在文本的颜色默认为黑色,但只有当condition === true时才会更新为红色。这是一个有点黑客,但工程为我的简单应用程序。

8xiog9wr

8xiog9wr8#

其他解决方案对我不起作用。经过一天的搜索,我得到了下面的解决方案。在我的问题中,我有两个用于RTL或LTR的CSS文件,如app.rtl.cssapp.ltr.css
创建一个功能组件Style,如下所示:

import React, { useState } from "react";

export default function Style(props) {
  const [stylePath, setStylePath] = useState(props.path);

  return (
    <div>
      <link rel="stylesheet" type="text/css" href={stylePath} />
    </div>
  );
}

然后你可以调用它,例如在App.js中:

function App() {
...
return (    
  <Style path={`/css/app.${direction}.css`} />
)}

direction param包含rtlltr,并确定应加载哪个文件。

相关问题