React bootstrap不能为我的React组件添加样式

46

昨天开始学习React,正在设置一个演示应用程序。环境如下:

  1. Typescript
  2. Webpack
  3. React和React DOM

我正在尝试设置Bootstrap样式。

我按照这个教程进行操作,但进行了修改以适应Typescript:

https://medium.com/@victorleungtw/how-to-use-webpack-with-react-and-bootstrap-b94d33765970

一切正常,页面显示登录表单,并且React-Bootstrap输出了Bootstrap HTMl。但是这些元素没有应用样式,它们只是一个普通的HTML页面,没有任何Bootstrap样式应用。 我不确定配置中缺少了什么:

webpack.config.js

我已经按照教程中提到的方法通过npm添加了加载器,但也调整了以便从css中设置Typescript模块。

module.exports = {
    entry: {
        catalog: "./src/apps/CatalogApp.tsx",
        auth: "./src/apps/AuthApp.tsx"
    },
    output: {
        filename: "[name].bundle.js",
        publicPath: "/build/",
        path: __dirname + "/dist"
    },

    // Enable sourcemaps for debugging webpack's output.
    devtool: "source-map",

    resolve: {
        // Add '.ts' and '.tsx' as resolvable extensions.
        extensions: [".ts", ".tsx", ".js", ".json"]
    },

    module: {
        rules: [
            // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
            {
                test: /\.tsx?$/,
                loader: "awesome-typescript-loader"
            },

            // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
            {
                enforce: "pre",
                test: /\.js$/,
                loader: "source-map-loader"
            },

            // css loader
            {
                test: /\.css$/,
                loader: "typings-for-css-modules-loader?modules"
            },

            {
                test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, 
                loader: 'url-loader?limit=10000&mimetype=application/font-woff'
              },
              {
                test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, 
                loader: 'url-loader?limit=10000&mimetype=application/octet-stream'
              },
              {
                test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, 
                loader: 'file-loader'
              },
              {
                test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, 
                loader: 'url-loader?limit=10000&mimetype=image/svg+xml'
              }
        ]
    },

    // When importing a module whose path matches one of the following, just
    // assume a corresponding global variable exists and use that instead.
    // This is important because it allows us to avoid bundling all of our
    // dependencies, which allows browsers to cache those libraries between builds.
    externals: {
        "react": "React",
        "react-dom": "ReactDOM"
    }
};

AuthApp.tsx

这是我的应用程序入口点。

import * as React from "react";
import * as ReactDOM from "react-dom";

import { SigninForm } from "../components/users/SigninForm";
import { MiniCart } from '../components/cart/MiniCart';
import { UserMenu } from '../components/users/UserMenu';
import * as bs from 'bootstrap/dist/css/bootstrap.css';
import * as bst from 'bootstrap/dist/css/bootstrap-theme.css';

if (document.getElementById("signin-form")) {
    ReactDOM.render(
        <SigninForm />,
        document.getElementById("signin-form")
    );
}

if (document.getElementById('cart')) {
    ReactDOM.render(
        <MiniCart />,
        document.getElementById('cart')
    );
}

if (document.getElementById('user-menu')) {
    ReactDOM.render(
        <UserMenu />,
        document.getElementById('user-menu')
    );
}

登录表单页面(SigninForm.tsx)

以及相应的用户界面。

import * as React from 'react';
import * as ReactDOM from "react-dom";
import { Button, Col, Row } from 'react-bootstrap';

import { Spinner } from '../shared/Spinner';

interface SigninFormProps {
}

interface SigninFormState {
  email: string;
  password: string;
}

export class SigninForm extends React.Component<SigninFormProps, SigninFormState> {

  constructor(props: SigninFormProps) {
    super(props);
    this.state = {
      email: '',
      password: ''
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event: any) {
    this.setState({ [event.target.name]: event.target.value });
  }

  handleSubmit(event: any) {
    event.preventDefault();
    console.log('Submitting form', this.state);
  }

  render() {
    return (
      <Row>
        <Col md={8}>
          <form className="signin-form" onSubmit={this.handleSubmit}>
            <div className="form-group">
              <label htmlFor="email">Email</label>
              <input id="email" name="email" type="email" value={this.state.email} onChange={this.handleChange} />
            </div>
            <div className="form-group">
              <label htmlFor="password">Password</label>
              <input id="password" name="password" type="password" value={this.state.password} onChange={this.handleChange} />
            </div>
            <Button>Submit</Button>
          </form>
        </Col>
        <Col md={4}>
          Right Side
      </Col>
      </Row>
    );
  }
}
10个回答

89

我遇到了同样的问题,这对我有用 -->

最后我使用npm安装了bootstrap:

  • 1) npm i --save bootstrap

然后,在index.js(我呈现App.js的地方)中,我从nodes_modules导入了bootstrap的压缩css文件,就像这样:

  • 2) import '../node_modules/bootstrap/dist/css/bootstrap.min.css';

现在响应式定位正常工作了(之前我看到react-bootstrap正确渲染了类名,但没有样式)。

注意:https://react-bootstrap.github.io/getting-started/introduction说你应该将css添加到index.html的头部。我用这种方式并没有成功。


1
我也尝试过将脚本标签添加到index.html文件中,但没有成功……可能是因为有些事情我还没有理解透彻。这个方法对我起作用了! - Mike Kellogg
对我来说,它只是'bootstrap/dist/css/bootstrap.min.css',无论您在'src'下面的哪个部分,都不需要明确从'node_modules'导入。 - khanna
你救了这一年,兄弟!! - Charleskimani

52

首先,你需要做的是使用NPM安装Bootstrap。

npm install --save bootstrap

然后

写这个语句时你需要使用Bootstrap的哪个组件,这在我的情况下有效。

import 'bootstrap/dist/css/bootstrap.css';

CSS样式将开始生效。 :)

编码愉快!


1
这个想法解决了我的问题。 - Aswin Prasad
3
导入'bootstrap/dist/css/bootstrap.css';对我来说没问题。 - Amit Dwivedi
这似乎是正确的答案。但可以通过解释原因来改进它...我怀疑原因是react-bootstrap只是将css包装为组件对象,但仍需要css。也许这提供了升级和主题bootstrap的能力...或者它提供了兼容版本的bootstrap与react-bootstrap的噩梦,哈哈,谁知道呢,我们拭目以待! - gunslingor
我想澄清一下,为什么我们下载任何特定的npm包时,bootstrap不会自动包含在内。js构建文件位于node_modules中,它们没有被导入或引用到你的前端代码中,因此为了包含bootstrap,我们必须使用import 'bootstrap/dist/css/bootstrap.css';来包含bootstrap css。 - Syed Umer Hasan

10

我不确定现在是否相关,但我查看了你的帖子。 然而,我可以使用react-bootstrap。 根据react-bootstrap,你需要添加

<link
    rel="stylesheet"
    href="https://maxcdn.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css"
    integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS"
    crossorigin="anonymous"
/>
我在我的index.html头标签中加入了一个链接,然后在我的app.js中加入了一行代码。

9
您使用的webpack配置与该篇中等文章略有不同。
在该篇中等文章中,作者使用style-loadercss-loader来处理css文件。
module.exports = {
  entry: './main.js',
  output: { path: __dirname, filename: 'bundle.js' },
  module: {
    loaders: [
      ...
      { 
        test: /\.css$/, 
        loader: "style-loader!css-loader" 
      },
      ...
    ]
  },
};

style-loader会将CSS代码注入到<style/>标签中。这就是为什么这个教程起作用的原因。

在你的webpack配置中,你使用typings-for-css-modules-loader来加载CSS。使用这个加载器,你需要将CSS类变量名传递给className

这意味着你应该像这样编写代码(简化一些代码):

import * as React from "react";
import * as bs from 'bootstrap/dist/css/bootstrap.css';
import * as bst from 'bootstrap/dist/css/bootstrap-theme.css';

import { Button, Col, Row } from 'react-bootstrap';

import { Spinner } from '../shared/Spinner';

export class SigninForm extends React.Component {
  ...
  render() {
    return (
      <Row>
        <Col md={8}>
          <form className={bt["signin-form"]} onSubmit={this.handleSubmit}>
            <div className={bt["form-group"]}>
              <label htmlFor="email">Email</label>
              <input id="email" name="email" type="email" value={this.state.email} onChange={this.handleChange} />
            </div>
            <Button>Submit</Button>
          </form>
        </Col>
        <Col md={4}>
          Right Side
      </Col>
      </Row>
    );
  }
}

bt[classname]传递给className

我认为这样做可以起作用。

顺便说一下,我发现另一篇中等文章使用了typings-for-css-modules-loader -> 链接


谢谢,我今天回家后会尝试这个。但是这不会修复布局组件,对吧?行和列标签也无法工作。 - Richard G
此外,这篇文章是我参考选择 typings css loader 的依据。它似乎得出结论,只需导入样式表即可正常工作,除非我理解有误... - Richard G
1
@RichardG React-Bootstrap文档中提到:“因为React-Bootstrap不依赖于非常精确的Bootstrap版本,所以我们不会附带任何包含的CSS”。因此,您需要自己包含Bootstrap CSS。 - Chen-Tai
实际上,他们也在使用样式加载器和命名导出选项。也许使用样式加载器可以解决这个问题。 - Richard G
是的,没错。你发布的中等文章是在js文件中导入bootstrap,并使用css-loader | style-loader来加载它。这是一个解决方法。 - Chen-Tai
好的,最终我使用了样式加载器,但必须关闭模块模式。然后它开始工作了。这很好,我想要全局的bootstrap类。然后我在应用程序的入口点导入文件,而不是在组件中。还调整了表单控件,使用react-bootstrap组件而不是构建自己的组件。 - Richard G

8
App.css 中只需粘贴以下导入内容:
@import "bootstrap/dist/css/bootstrap.css";

7
请尝试将这行代码添加到 index.js 文件中:

import 'bootstrap/dist/css/bootstrap.min.css';

将其添加到 App.js 文件中并不适用于我。

好的回答。谢谢。 - Gass

5
你是否使用的是 node v16.15.0 或更高版本?
请根据以下方式之一进行操作:
1. 使用 Yarn?运行 - yarn add react-bootstrap bootstrap 2. 使用 npm?运行 - npm install react-bootstrap bootstrap 然后在你的 App.js 文件中添加这一行代码:import 'bootstrap/dist/css/bootstrap.css'; 最后,重新启动你的 React 应用程序。之后它应该可以正常工作了。

2

你需要在你的代码中导入Bootstrap库

import 'bootstrap/dist/css/bootstrap.css';

在你的app.js文件中导入这个库

这在我的情况下有效


我需要在 main.tsx 中导入它。 - user3286381
这对我来说是个问题。谢谢! - undefined

1
除了 bootstrap.min.js,我们还需要使用 bootstrap.min.css 才能使 bootstrap 正常工作。访问 https://www.bootstrapcdn.com/,复制 CSS 和 JavaScript 下的链接,并将其粘贴到 HTML 文件 的 head 标签下。
按以下方式使用,并根据需要更改 bootstrap 版本。

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap**@5.1.1**/dist/css/bootstrap.min.css"  crossorigin="anonymous"/>
<script src="https://cdn.jsdelivr.net/npm/bootstrap**@5.1.0**/dist/js/bootstrap.min.js" crossorigin="anonymous"></script>


0

React-Bootstrap 官方也提供了解决方案:

1 - 导入要使用的组件:

import Button from 'react-bootstrap/Button';

或者不太理想的方式 import { Button } from 'react-bootstrap';

2 - 导入所需的样式表,以便正确应用组件的样式:

import 'bootstrap/dist/css/bootstrap.min.css';

刷新页面,现在 Bootstrap 的默认样式应该已经被正确应用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接