使用' classnames'可扩展的React CSS考虑到BEM

时间:2017-02-23 16:03:41

标签: javascript css reactjs sass jsx

所以,在这里反应新手......我开始说我有一个简单的单页面应用程序,它包含几个简单的页面。

使用react-router我有一个自上而下的'为我的组件设置。为了让您对我的SPA结构有一个基本的了解,请参阅下文:

index -- layout(react routers) --
                                |--About Page
                                |--Home Page
                                |--Contact Page

我正在渲染一个名为" GlobalHero"来自我的主页组件。

以下是GlobalHero.jsx组件。

import React from "react";
var classNames = require('classnames');
import s from '../../../index.scss';

class GlobalHero extends React.Component {

    constructor() {
        super();
        //sets initial state
        this.state = {
            fadeIn: "",
            titleSelected: "",
            subTitleSelected: ""
        };
    }

    // <<========= ON COMPONENT RENDER =========
    componentDidMount = () => {
        console.log("GlobalHero");
        console.log(this.props);
        this.handleClass("fadeIn");
    }
    // =========>>

    // <<========= CONTROLS THE STATE =========
    handleClass = (param) => {
        if (param === "fadeIn" && this.state.fadeIn != "true") {
            this.setState({fadeIn: "true"});
        }
        if (param === "titleSelected" && this.state.titleSelected != "true") {
            this.setState({titleSelected: "true"});
        }
        if (param === "subTitleSelected" && this.state.subTitleSelected != "true") {
            this.setState({subTitleSelected: "true"});
        }
    }
    // =========>>

    render() {

        const heroImg = require(`../../../images/hero${this.props.page}.jpg`);

        //REMOVES CLASS IN REALTIME BASED ON STATE'S VALUE =========
        var containerClasses = classNames({
            [s['text-center']]: true,
            [s["hidden"]]: this.state.fadeIn != "true",
            [s["fadeIn"]]: this.state.fadeIn === "true"
        });
        var titleClasses = classNames({
            [s['blue']]: this.state.titleSelected === "true"
        });
        var subTitleClasses = classNames({
            [s['subTitle']]: true,
            [s['text-center']]: true,
            [s['blue']]: this.state.subTitleSelected === "true"
        });
        // =========>>

        return (
            <div className={s["container-fluid"]}>
                <div className={s["row"]}>
                    <div className={s["col-lg-16"]}>

                        <div className={containerClasses}>
                            <img src={heroImg} className={s["hero__img"]}></img>
                            <h1 onClick={() => this.handleClass("titleSelected")} className={titleClasses}>{this.props.page}!</h1>
                            <p className={subTitleClasses} onClick={() => this.handleClass("subTitleSelected")}>{this.props.name}, {this.props.age}, {this.props.city}</p>
                        </div>

                    </div>
                </div>
            </div>
        );
    }
}

export default GlobalHero;

我注意到为组件的元素分配一些简单的类名有很多复杂性。

  

我想知道这样做是否有更好的做法?也许   使用外部js页面来管理我的类名?

任何输入或adivce表示赞赏...谢谢你的支持。

1 个答案:

答案 0 :(得分:2)

您的标题提及BEM,但看起来您正在使用CSS Modules,其灵感来自类似的想法,但并非相同。

无论如何,这是非常主观的,但我有一些想法太多不适合评论:

  • 假设您正在通过Webpack的css-loader使用css模块,您可以使用camelCase使您的样式属性更加JS友好:

    loader: "css-loader?modules&camelCase"
    

    现在,对于.text-center css类名,您只需使用s.textCenter代替s["test-center"]

  • 你可以更好地对其进行组件化:首先,你可以为单个组件做很多事情,但你可以break it down into a few smaller components that each have a single responsibility(例如容器,标题,副标题)。其次,你的handleClass()方法做得很多,当你可以只有简单的处理程序调用{​​{1}}而不知道类名时。换句话说,组件应该具有props和state,只有setState()函数处理如何将其转换为要呈现的类名。在设置之前,您还真的不需要检查状态的当前值。只需将其设置为应该是什么,让React为您优化渲染性能。
  • 你有使用字符串render()"true"存储的布尔状态标志...这使得它处理起来很嘈杂,只是存储为布尔值。
  • 你有很多"false"这是没有必要的;如果你总是希望渲染一个类名,只需将它作为参数传递给[s["class-name"]]: true

    classNames
  • 没有理由在classNames(s.subTitle, { [s.blue]: this.state.subTitleSelected }) 上调用处理程序,只需按照您想要的状态初始化状态。
  • 看起来你正在使用bootstrap CSS而不是React Bootstrap组件。我强烈建议使用React Bootstrap。

把它放在一起我会有类似的东西:

componentDidMount

将它分解为像这样的较小组件并不是完全必要的,但请注意从class GlobalHero extends React.Component { state = { fadeIn: true, titleSelected: false, subTitleSelected: false }; handleTitleClick = () => { this.setState({titleSelected: true}); }; handleSubTitleClick = () => { this.setState({subTitleSelected: true}); }; render() { return ( <Grid fluid> <Row> <Col lg={16}> <HeroContainer fadeIn={this.state.fadeIn}> <HeroImage page={this.props.page} /> <HeroTitle selected={this.state.titleSelected} onClick={this.handleTitleClick} page={this.props.page} /> <HeroSubTitle selected={this.state.subTitleSelected} onClick={this.handleSubTitleClick} name={this.props.name} age={this.props.age} city={this.props.city} /> </HeroContainer> </Col> </Row> </Grid> ); } } const HeroContainer = ({fadeIn, children}) => { return ( <div className={classNames(s.textCenter, fadeIn ? s.fadeIn : s.hidden)}> {children} </div> ); }; const HeroImage = ({page}) => { const heroImg = require(`../../../images/hero${page}.jpg`); return ( <img src={heroImg} className={s.heroImg} /> ); }; const HeroTitle = ({onClick, selected, page}) => ( <h1 onClick={onClick} className={selected ? s.blue : null}>{page}!</h1> ); const HeroSubTitle = ({onClick, selected, name, age, city}) => ( <p className={classNames(s.subTitle, s.textCenter, { [s.blue]: selected })} onClick={onClick}> {name}, {age}, {city} </p> ); 的角度来看它对样式没有任何作用,它只是设置道具和状态,而小部分没有状态,它们只是根据道具渲染正确的样式。

PS 也许这应该转移到Code Reviews