1. Features of the componentized CSS

  1. You can write local CSS: CSS has its own scope and does not contaminate the native components in other components.
  2. You can write dynamic CSS: you can get some state of the current component and generate different CSS styles according to the state changes;
  3. Support all CSS features: pseudo class, animation, media query, etc.
  4. Write simple and convenient, preferably consistent CSS style features;
  5. And so on…

CSS in React

In fact, CSS has always been a pain point in React, which has been teased and criticized by many developers

Vue does this better than React:

  1. Vue is written in a. Vue file<style><style>Tag to write your own style
  2. You can determine whether a written style is globally or locally valid by adding the scoped attribute
  3. through langProperty to set as you like less,sassIsopreprocessor
  4. Use inline style styles to set and change CSS according to the latest state.
  5. And so on…

Vue is not perfect in CSS, but it is simple, natural and convenient. At least the unified style will not be used by multiple developers or projects.

React, by contrast, does not officially provide a unified style for React:

  1. From ordinary CSS, to CSS Modules, to CSS in JS, there are dozens of different solutions, hundreds of different libraries;
  2. Everyone is looking for the best or most suitable CSS solution, but so far there is no unified solution;

2.1 Inline style

Inline styles are the official recommended way to write CSS styles:

  1. Style accepts a JavaScript object with a small camel named attribute, rather than a CSS string;
  2. And you can reference the state in state to set the associated style;
import React, { PureComponent } from 'react'

export default class App extends PureComponent {
  constructor(props) {
    super(props)

    this.state = {
      pStyle: {
        color: 'purple'.marginTop: '10px'}}}render() {
    return (
      <div>{/* Here we can pass an object to represent the inline style note: the key value of this object can only accept small humps and its value must be a string */}<h3 style={{ fontSize: '30px', color: 'red'}} >This is the H3 tag</h3>{/* Use inline style to read variables in state as p tags */}<p style={ this.state.pStyle} >This is a P tag</p>
      </div>)}}Copy the code

Advantages of inline style:

  1. Inline styles, no conflicts between styles
  2. The state in the current state can be dynamically retrieved

Disadvantages of inline style:

  1. You need to use the hump symbol
  2. Some styles don’t have prompts
  3. Lots of styles, code mess
  4. Some styles cannot be written (such as pseudo-classes/pseudo-elements)

So the official hope is that inline is written in combination with normal CSS

2.2 the original CSS

Where Home is the component, index.js is the entry file, style.js is the style file

App.js

import React, { PureComponent, Fragment } from 'react'


// When importing, import the folder directly
// This is because webPack uses the index.js folder as the default entry file when packaging
import Home from './Home'

export default class App extends PureComponent {
  render() {
    return (
      <Fragment>{/* React components are not declared with componets */}<Home />
      </Fragment>)}}Copy the code

index.js

import React, { PureComponent, Fragment } from 'react'

// Style files need to be imported before they can be used
import './style.css'

class Home extends PureComponent {
  render() {
   return (
    <Fragment>
      <h3 className="title">This is the Home component</h3>
      <article className="content">This is what's in the Home component</article>
    </Fragment>)}}export default Home
Copy the code

style.css

.title {
  color: red
}

.content {
  color: skyblue;
}
Copy the code

Existing problems

  1. The style will be overwritten

    import React, { PureComponent, Fragment } from 'react'
    
    
    import Home from './Home'
    import Profile from './Profile'
    
    export default class App extends PureComponent {
      render() {
        return (
          <Fragment>
            <Home />
            <Profile />
          </Fragment>)}}Copy the code

    Add a new component Profile to the end of the Home component

    The style.css content in the profile component is as follows

    .title {
      color: pink;
    }
    
    .content {
      color: green;
    }
    Copy the code

    In this case, the interface looks like this

    You can see that the styles in the profile are overwritten by the styles in the Home

    • Try solutions:

      #Profile .title {
        color: pink;
      }
      
      #Profile > .content {
        color: green;
      }
      Copy the code

      Precede each style with a unique identifier, or use the direct descendant selector to find the unique element and set the style

      But this can lead to extremely complicated style writing,

      And writing this way can lead to style overwriting due to style weight issues (e.g. # profile.title weight ratio). Profile. title high), which is bad for maintenance

Conclusion:

Normal CSS is usually written in a separate file and introduced later

This is written in the same way as in normal web development:

  • If we follow the common web standards to write, then there won’t be too much of a problem;
  • However, in componentized development, we always want components to be independent modules, and even the styles are only valid within themselves, and do not affect each other.
  • But common CSS are global CSS, and styles affect each other;

2.3 css module

  • CSS modules are not a React specific solution, but can be used in any environment that uses a webPack-like configuration.

    • However, if we use modules in other projects, we need to configure them ourselves, such as modules: True in webpack.config.js
  • The React scaffolding has CSS modules built into it:

    • . CSS /. Less /. SCSS etc. Style files are modified into the module. The CSS /. The module. The less /. The module. The SCSS, etc.;
    • Then it can be referenced and used;
import React, { PureComponent, Fragment } from 'react'

// In this way, the style file is introduced,
// Enable webPack to compile this file automatically when it is packaged
// But since we didn't define a variable to point to the introduced module,
// So we can't use it
// import './style.css'

// Rename the original CSS file to module. CSS to be written in the same way as the previous CSS
import style from './style.module.css'

class Home extends PureComponent {
  render() {
   return (
    <Fragment>
      <h3 className={ style.title} >This is the Home component</h3>
      <article className={ style.content} >This is what's in the Home component</article>
    </Fragment>)}}export default Home
Copy the code

You can see that when compiled, the style is style_style name _ unique, so that all styles are unique and not duplicated

But this approach has its drawbacks:

  • The name of the referenced class, which cannot use the hyphen (.home-title), is unreadable in JavaScript;
  • All classnames must be written in the {style.className} form;
  • It is not convenient to change some styles dynamically, so you still need to use inline styles.
{/* If you want to use state in CSS in Module, you must combine className and style. This is similar to vue}
<h3 className={ style.title } style={{ color: this.state.color}}> This is Home component </h3>Copy the code

2.4 styled – components

CSS in JS

In fact, CSS in JS is mentioned in the official documentation:

  • “Css-in-js” refers to a pattern in which CSS is generated by JavaScript rather than defined in external files;
  • Note that this functionality is not part of React, but is provided by third-party libraries. React is not clear about how styles should be defined;

In traditional front-end development, we often separate structure (HTML), style (CSS), and logic (JavaScript).

  • However, as we mentioned in the previous study, React thought that logic and UI were inseparable, hence the syntax of JSX.
  • Style? Styles are also part of the UI;
  • In fact, csS-in-JS mode is a way to write style (CSS) into JavaScript, and can easily use JavaScript state;
  • So React is calledAll in JS;

advantages

  1. Css-in-js endows CSS with some capabilities through JavaScript, including style nesting similar to CSS preprocessor, function definition, logic reuse, dynamic modification state, etc.
  2. CSS preprocessors still have some capabilities, but getting dynamic state is still a tricky point;
  3. Therefore, CSS-in-JS is currently the most popular solution for writing CSS with React;

Common CSS in JS libraries

  • styled-components
  • emotion
  • glamorous

Styled – Components is still arguably the most popular CSS-in-JS library in the community, so we will practice using styled- Components

Template string

Tagged Template Literals are also used in another way:

Normally, we call a function by its name (), but there is another way to call a function:

function printStr(. args) {
    console.log(args)
}

printStr`Tagged Template Literals`
Copy the code

const name = 'Klaus'
const age = 23

function printStr(. args) {
    console.log(args)
}

printStr`My name is ${name}, age is ${age}`
Copy the code

  • The template string was split;

  • The first element is an array, which is a combination of strings split by module strings.

  • The following elements are passed in as module strings

In the Styled Component, this is how the module string is parsed, resulting in the style we want

Styled – Components Essentially creates a component through calls to functions:

  • This component is automatically added to a non-repeating class;
  • Styled – Components adds related styles to the class
import React, { PureComponent } from 'react'

import styled from 'styled-components'

// This generates a div tag wrapped around the component
// A unique identifying class name is automatically added to this component
// When setting styles in the Styled component, the style ending semicolon on each line cannot be omitted
const HomeWrapper = styled.div` color: red; font-size: 20px; `

class Home extends PureComponent {
  constructor(props) {
    super(props)

    this.state = {
      color: 'skyblue'}}render() {
   return (
      <HomeWrapper>{/* The generated component is wrapped so that its children can inherit and use its corresponding style */}<h3>This is the Home component</h3>
       <article>This is what's in the Home component</article>
      </HomeWrapper>)}}export default Home
Copy the code

Styles can be written in styled- Components

Note: the essence of this is to call js functions and generate components, so if it is exported to a separate file, it is a JS file, not a CSS file

const HomeWrapper = styled.div` color: red; font-size: 20px; h3 { color: skyblue; &:hover { color: green; } } article { &::after { content: 'after' } } `
Copy the code

Styled - Components Has several features

  1. Props to penetrate
import React, { PureComponent, Fragment } from 'react'
import styled from 'styled-components'


const XFInput = styled.input` background-color: lightgray; `

export default class Home extends PureComponent {
  render() {
    return (
      <Fragment>{/* Because XFInput is finally converted to an input tag with a style, this type is set on XFInput but is still added to the final input tag, which is called props through */}<XFInput type="password" />
      </Fragment>)}}Copy the code
  1. Basic use of attrs
import React, { PureComponent, Fragment } from 'react'
import styled from 'styled-components'

/* attrs is a function whose argument is an object and whose return value is still a function, so you can continue to call it using the tag template string, which is a chain call. When writing styles, its value can pass an arrow. The function has one parameter, props, which is the configuration object in attrs */
const XFInput = styled.input.attrs({
  color: 'lightgray'
})`
  background-color: ${ props => props.color };
`

export default class Home extends PureComponent {
  render() {
    return (
      <Fragment>
        <XFInput type="password" />
      </Fragment>)}}Copy the code
  1. Pass state as props

    import React, { PureComponent, Fragment } from 'react'
    import styled from 'styled-components'
    
    
    /* The props source is 2. Attrs configuration object 2. Props tips: If the names of the props passed by the component and the properties of the attrs configuration object overlap, the corresponding properties of attrs are overridden */
    const XFInput = styled.input.attrs({
      bgColor: 'lightgray'
    })`
      background-color: ${ props => props.bgColor };
      color: ${ props => props.color }
    `
    
    export default class Home extends PureComponent {
      constructor(props) {
        super(props)
    
        this.state = {
          color: 'red'}}render() {
        return (
          <Fragment>{/* Pass style values in state to scoped-compoents. Style attributes written here are dynamic and will change. Attrs attributes are fixed and will not change.<XFInput type="password" color={ this.state.color} / >
          </Fragment>)}}Copy the code

With the above features, styles can be dynamically set to React and rendered

High order use

  1. inheritance
import React, { PureComponent, Fragment } from 'react'
import styled from 'styled-components'

const WXFButton =  styled.button` padding: 8px 30px; border-radius: 5px; `
/* Passes a parameter in the Styled function, indicating that the style value in the Styled component inherits from the relative style in the passed styled component
const WXFPrimaryButton = styled(WXFButton)` color: #fff; background-color: skyblue; `


export default class Home extends PureComponent {
  render() {
    return (
      <Fragment>
        <WXFPrimaryButton>
          primary-button
        </WXFPrimaryButton>
      </Fragment>)}}Copy the code
  1. Use of theme (setting global style property values that need to be used globally or shared)

app.js

import React, { PureComponent } from 'react'
import { ThemeProvider } from 'styled-components'

import Home from './Home'
import Profile from './Profile'


export default class App extends PureComponent {
  render() {
    return (
      <ThemeProvider theme={{ color: 'skyblue', fontSize: '30px' }}>
        <Home />
        <Profile />
      </ThemeProvider>)}}Copy the code

Home.js

import React, { PureComponent, Fragment } from 'react'
import styled from 'styled-components'

const XFSpan = styled.span`
  color: ${ props => props.theme.color };
  font-size: ${ props => props.theme.fontSize };
`

export default class Home extends PureComponent {
  render() {
    return (
      <Fragment>
        <XFSpan>This is the Styled component using the theme</XFSpan>
      </Fragment>)}}Copy the code

2.5 Coexistence of multiple class names

Adding a class to vue is a very simple matter:

Object syntax

Array syntax

Arrays and objects coexist

React in JSX gives us plenty of flexibility as developers. You can use some logic to decide whether or not to add classes, just as you would in JavaScript code:

React is written in its native style

<h1 className="foo bar active"> This is H1 header </ H1 > {/* foo must be followed by a space to distinguish between classes */}

{/* The termhead operators must be followed by () to indicate that they are a whole. If not, foo will be lost at compile time and the resulting style 'active' will be */ without 'foo'}
<h1 className={'foo ' + (isActive ? 'active' : ' '}> This is the H1 header </ H1 > {/* The logic operator must also be wrapped in parentheses. If it is not included, the compiled style will still be */ without foo}
<h1 className={'foo ' + (isActive && 'active'}> This is the H1 header </ H1 ><h1 className={ ['foo'(isActive ? 'active' :"')".join(' ') }>This is the H1 heading</h1>
Copy the code

Use a third-party style library (classNames) to help us write the React style

<h1 className={className('foo'.'bar'.'active'}> This is the H1 header </ H1 ><h1 className={className({'active': isActive }, 'foo')} >This is the H1 heading</h1>

{/* All values will be converted to false values and will not be rendered e.g. null, undefined, 0 */}
<h1 className={className({'active': isActive }, 'foo'.null.undefined}> This is the H1 header </ H1 > {/* But here 10 is converted to the string 10 as a valid class name */}
<h1 className={className({'active': isActive }, 'foo'.10}> This is the H1 header </ H1 ><h1 className={className(['foo', 'active'])} >This is the H1 heading</h1>

<h1 className={className(['foo'{'active': isActive }])}>This is the H1 heading</h1>
Copy the code

Previous article on advanced components and component supplements