I’m not sure if decorators were introduced in ES 6 or ES 7, either way, but I don’t care… React works well with React. React works well with React. So let’s talk about that.

I. Environment construction

I built a React development environment and used it in conjunction with Babel’s plugin, babel-plugin-transform-decorators-Legacy, which allows you to write decorators.

Making address: https://github.com/zhongdeming428/HOC

You can run the following command to clone:

$ git clone https://github.com/zhongdeming428/HOC.git
Copy the code

After cloning, you can try it!

Basic use of decorators

A decorator is itself a function, and it’s pretty simple to use. It just decorates a class or a class’s function. Using the @ call, just throw it in front of the class or method you want to decorate. But there are subtle differences in how you modify classes and class functions.

class A {
    @sayB
    sayA() {
        console.log('a'); }}function sayB(target, name, descriptor) {
    // ...
}
Copy the code

When you decorate a class function with a decorator, you can take three arguments. The first is the object to be decorated, the second is the name of the property to be decorated, and the third is the property descriptor. You can try it on the project I built.

When decorating a class with a decorator, you can only accept one argument, target. This is different from the case above:

@APlus
class A {}function APlus(target, name, descriptor) {
    / /... Print, and you can see that the name and descriptor are undefined.
}
Copy the code

In addition, the decorator can accept arguments and return a new function that conforms to the decorator specification, which allows you to customize the decorator behavior. Such as:

@attach2Prop({ name: 'A' })
class A {

}

@attach2Prop({ name: 'B' })
class B {}function attach2Prop(obj) {
    return function(target) { target.prototype.$data = obj; }}console.log((new A()).$data.name);
console.log((new B()).$data.name);
Copy the code

The result will print A and B.

This makes it possible to decorate with different behaviors using the same decorator.

So what’s great about React?

React

(1) Simplify the use of React-Redux

When using React-Redux, we used to define the container component after defining the UI component:

class UIComponent extends React.Component {}const ContainerComponent = connect(mapState2Props, mapDispatch2Props)(UIComponent);

export default ContainerComponent;
Copy the code

With decorators:

@connect(mapState2Props, mapDispatch2Props)
class UIComponent extends React.Component {}export default UIComponent;
Copy the code

This achieves the same effect with simplified code and saves the hassle of naming container components… The code is much cleaner.

(2) Customize higher-order components

The container component in the previous section is actually a higher-order component, but we sometimes define higher-order components ourselves to enable higher-level reuse of code.

For example, we made a component library, which has a part of the component is a functional feature, that is, can be dragged; Another example is the mobile component we do, which needs to implement a left swipe deletion function. Do we need to write drag-and-drop or left-swipe delete logic for each component that has this feature?

Obviously no, we can implement a purely logical component, not a UI component, whose job is to make your UI component do something specific. Like the left swipe to delete or drag mentioned above.

This purely logical component can be a decorator, a higher-order component.

In the development environment I built, I implemented a simple, high-level component that makes your UI component appear as a hand when the mouse slides in.

The decorator code is as follows:

// src/decorators/CursorPointer.js
import React from 'react';

export default Component => class extends React.Component {
  render() {
    return <div style={{cursor: 'pointer', display: 'inline-block'}} >
      <Component/>
    </div>}}Copy the code

The decorator (higher-order component) takes a React component as an argument and returns a new React component. The implementation is as simple as wrapping a div and adding a style, and that’s it. All future components decorated with it will have this feature.

Use this decorator:

import React from 'react';
import Clickable from '.. /decorators/CursorPointer';

@Clickable
class ClickablePanel extends React.Component {
  render() {
    return <div className="panel">

    </div>}}export default ClickablePanel;
Copy the code

Combine decorators with higher-order components to greatly optimize your React code!