What is styled – components

Styled – components website

Styled – Components is a CSS in JS scheme

advantage

  • Easy to set dynamic styles
  • Styled – Components The generated className is unique, and there is no need to worry about className conflicts
  • Easy to use, no need to configure Webpack, out of the box
  • Dealing with CSS Modules variables is tricky for the SSR class framework, so styled- Components is used for the scheme

Simple and easy to implement

For the Style network, let’s implement a V-Styled style. The following implementation and source discrepancy, a lot of simplification

Simple usage

Styled – Components are used as follows:

const Div = styled.div`
  border: 1px solid red;
  font-size: ${(props) => (props.fs ? props.fs : '20px')};
  color: red;
  border-radius: ${(props) => (props.radius ? props.radius : ' ')};
`;

function App() {
  return (
    <Div fs='30px' radius='10px'>
      Hello world
    </Div>
  );
}
Copy the code

As you can see from above, styled- Components uses a labeled template string. Styled (‘div’), and styled(‘div’) returns a tag template string function

First, let’s declare a function v

function v(tag) {}
Copy the code

For our V-Styled also to support multiple HTML tags, the following transformation is required:

let domElement = ['a'.'span'. ] ; domElements.forEach((domElement) = > {
  v[domElement] = v(domElement);
});
Copy the code

V (‘div’) returns a tag template string function to modify the implementation of function v

function v(tag) {
  return (strings: any[], ... args: any) = > {};
}
Copy the code

Step 1: Work with the CSS content

A tagged template string whose first argument is a strings array and the remaining arguments are related to the expression ${expression}

First, we declare a DIV component

// Declare a Div component

const Div = v.div`
  border: 1px solid red;
  font-size: ${(props) => (props.fs ? props.fs : '20px')};
  color: red;
  border-radius: ${(props) => (props.radius ? props.radius : ' ')};
`;

const APP = () = >{
   / / use
   return  <Div fs="12px" radius="4px">
}
Copy the code

So if we do nothing, the function v prints:

function v(tag) {
  return (strings: any[], ... args: any) = > {
    /** The first parameter strings is: [" border: 1px solid red; font-size: ", "; color: red; border-radius: ", "; "] ƒ (
    console.log(strings, args);
  };
}
Copy the code

Once we have the parameters passed by the template string, we need to process it by executing the passed expression and then putting it back in its original position. We want to generate CSS rules like this:

 {
  border: 1px solid red;
  font-size: 12px;
  color: red;
  border-radius: 4px;
}
Copy the code

${(props) => (props. Fs? Fs: ‘props ‘)}, ${(props) => (props. Radius: ”)} we need to mix the first argument, strings, with the rest of the parameters, and write an exchange function:

const interleave = (strings, interpolations) = > {
  const result = [strings[0]].for (let i = 0, len = interpolations.length; i < len; i += 1) {
    result.push(interpolations[i], strings[i + 1]);
  }
  return result;
};
Copy the code

Now we can mix the parameters and the result is:

function v(tag) {
  return (strings: any[], ... args: any) = > {
    const cssRules = interleave(strings, args);
    / * * parameters as output: [" border: 1 px solid red; the font - size: ", ƒ (), "; color: red; border - the radius: ", ƒ (), "; "] * * /
    console.log(cssRules);
  };
}
Copy the code

All that is left to do is to execute the output of the expression passed in, and then concatenate the array into a string to generate the corresponding CSS rules. For ease of use later, we call the result of the mix cssRules

Step 2: Generate the React Element

Because we need to support multiple DOM tags, we use React. CreateElement to create the domElement

function styledComponentImpl() {
  return React.createElement('div', { className: 'test' });
}
Copy the code

We call styledComponentImpl() to create a div tag with className test

Back to our function v, we need to pass the cssRules, tag, and className information to styledComponentImpl. It’s very simple. Tags, rules and other information are passed to a StyledComponentL using the WrappedStyledComponent object.

function v(tag: string) {
  return (strings: any[], ... args: any) = > {
    const cssRules = interleave(strings, args);

    let WrappedStyledComponent: any;

    // Declare a function component
    const forwardRef = (props: any, ref: any) = >
      styledComponentImpl(WrappedStyledComponent, props, ref);
    WrappedStyledComponent = React.forwardRef(forwardRef);

    WrappedStyledComponent.tag = tag;
    WrappedStyledComponent.rules = rules;
    // simply generate a non-repeating className
    WrappedStyledComponent.className = `v-${uuidv4()}`;

    return WrappedStyledComponent;
  };
}
Copy the code

After obtaining cssRules,className, and Tag, you can evaluate styles, insert styles, and return the React Element in response. StyledComponentImpl implements the following:

// Create react Element
function styledComponentImpl(
forwardedComponent: IStyledComponent,
props: Object,
forwardedRef: Ref<any>,
) {
const{ children, ... restProps } = props;// Get cssRules, className, tag
const{cssRules, className, tag} = forwardedComponent;// Here we pass props to an expression in the template string to execute
const css = cssRules
.map((r: any) = > (typeof r === "function" ? r(restProps) : r))
.join("");

// Generate the style and insert the style into the head
const injectedCSS = `.${className} { ${css}} `;
insertCss(injectedCSS);

// Return the React Element with the className
return React.createElement(tag, { className }, children);
}
Copy the code

Step 3: Insert styles into head

Get the styleSheet instance, and then call its insertRule method to insert the style, as shown in the following example:

// Insert CSS into head
function insertCss(css: string, index = 0) {
  const { styleSheets } = document;
  styleSheets[0].insertRule(css, index);
}
Copy the code

talk is cheap , show you the code

Author reference styled- Components source code simple implementation, implementation address

Styled – the components of the problem

Frequent changes in props generate a lot of redundant styles

Each time a new props is passed in, a new className is generated, resulting in a lot of redundant styles. Therefore, if the props of the style component change frequently, it is recommended to use inline style directly. Repetition demo

other

Styled components uses monorepo to manage the code, and after starting the example in the sandbox directory yarn Start, we go to the styled components source directory, and after making changes, sandbox will listen for file changes. The Styled – Components code will be rebuilt. The local debugging experience is excellent