“This article has participated in the call for good writing activities, click to view: the back end, the big front end double track submission, 20,000 yuan prize pool waiting for you to challenge!”

preface

I wrote a business project a little over a year ago, and I went straight into the Vue + TypeScript combo (I never wrote TypeScript before). Now when I look back, the garbage code hides in the dim lights.

Taking the opportunity of this new requirement, I took the initiative to check back and optimize the code on the basis of completing the requirement. There were several times when people could not bear to think back, but I still applied the experience accumulated over the past year to this reconstruction, which felt quite interesting.

component

None of the code presented in this article is the full version code

The object of reconstruction is a reusable component of a front-end desktop system. Let’s take a look at the differences in the use of components before and after optimization:

<! -- Before optimization --><template>
  <LetterDetail
    :data="letterDetailData"
    :info="cirInfo"
    :modal="isShow"
    @update-info="handleUpdateInfo"
    @close-modal="handleCloseLetterDetail">
  </LetterDetail>
</template>

<script lang="ts">
export default class LetterDetail extends Vue {
  private isShow: boolean = false
  private cirInfo: Array<object> = false
  private letterDetailData: object = false

  private handleUpdateInfo(id: string): void {
    this._getLetterDetail(id)
  }

  private handleCloseLetterDetail(letterId: string): void {
    api.getLetterDetail(letterId).then((res) = >{... }}})</script>
Copy the code

The component name LetterDetail is a reusable component, and it is reused multiple times within different business components.

  • Data is the incoming letter detail property
  • Info is the attribute of incoming logistics information
  • Modal is the switch property of the component that is passed in whether to display the details of the letter
  • Update-info is the Emit event with the message ID input
  • Close-modal is the Emit event when the letter detail component is closed

Looks very complicated, actually NO!! It was cutie a year and a half ago who made this code complicated. Don’t ask me why. You need to take the time machine back and ask her.

Now, based on the LetterDetail component before optimization, we know what that component does, right? It’s used to display the details of the letter and the logistics, but it’s also a kind of modal box that can be opened and closed, and even if you’re working inside the component to update the status of the letter you need to update the display information at any time. Let’s look at the optimized calling code:

<template>
  <LetterDetail
    :visible="isLetterDetailShow"
    :id="mailId"
    @closed="handleLetterDetailClosed">
  </LetterDetail>
</template>

<script lang="ts">
export default class LetterDetail extends Vue {
  private isLetterDetailShow: boolean = false // Whether to display the letter details component
  private mailId: string =  ' ' / / mail ID

  private handleLetterDetailClosed(): void {
    this.isLetterDetailShow = false
    this.mailId = ' '}}</script>
Copy the code

First, we reduced the number of lines of code, including reducing the data and info properties of the letter details component and the update-info event thrown.

A few key points about refactoring in small ways, even on component calls:

  1. Comments: Add comments to code where appropriate, such as HTML, data, methods…
  2. named: Reference existing component libraries for naming, for example
    • visibleThe attribute name (originally modal) references the Dialog in Element;
    • Boolean switch class data variables are as named as possibleisXXXShowisLetterDetailShow;
    • closedEvent names (originally close-modal) also refer to Element dialogs;
    • Event handling methods should be named asHandleXXX verbshandleLetterDetailClosed;

    * In fact, naming belongs to a code specification, it is not right or wrong only relatively good or bad, this obsessive-compulsive patients also accumulated an article, the next article. (Flag here)Give me a thumbs up

  3. logic: Before optimization, data and INFO were passed in as attributes. After optimization, the code was changed to only pass in the letter ID. It shows that the train of thought has gone fromGet data outside the componentChange toPassing in the least data requests more data within the component as needed. Due to some data optimization, a lot of logic problems have to be revised accordingly. For example, previously the component needed update-info to synchronize the displayed data, but the optimized code has already integrated the data into the component to fetch and update, so the corresponding events are not required.

The body of the open

A, comments,

The code before optimization had no comments at all, so even when I redeveloped the new feature more than a year later, the code took a long time to read, and with that distorted name, it was “awesome.”

Code optimization on comments can start in three places:

1.1 HTML

<template>
  <div id="letter-detail">
    <el-dialog title="Details of Letter">
      <div>
        <! -- Basic information.<! -- Basic information

        <! -- Supplementary remarks S -->.<! -- Supplementary remarks E -->

        <! -- Logistics information S -->.<! -- Logistics information E->
      </div>
      <div slot="footer" class="dialog-footer">
        <! Rcv_snd: 1 But the recipient is not the sender rcv_snd: 2 But the sender is not the recipient -->
        <el-button v-show=! "" isYQS" v-if="letterDetail.rcv_snd == '2' || letterDetail.rcv_snd == '0'">Withdraw the letter</el-button>
        <el-button v-show=! "" isYQS" v-if="letterDetail.rcv_snd == '1' || letterDetail.rcv_snd == '0'">Sign after receiving STH</el-button>
        <el-button v-show=! "" isYQS" v-if="letterDetail.rcv_snd == '1' || letterDetail.rcv_snd == '0'">Set up a proxy</el-button>
        <el-button v-show=! "" isYQS" v-if="letterDetail.rcv_snd == '0' || letterDetail.rcv_snd == '1' || letterDetail.rcv_snd == '2'">Exception setting and handling</el-button>
        <el-button v-if="letterDetail.rcv_snd == '0' || letterDetail.rcv_snd == '1' || letterDetail.rcv_snd == '2'">Add Supplementary Remarks</el-button>
      </div>
    </el-dialog>
    <! -- Set the signer mode box S -->
    <el-dialog...
    </el-dialog>
    <! -- Set the signer mode box E -->
    
    <! -- Exception setting and handling mode box S -->
    <el-dialog...
    </el-dialog>
    <! -- Exception setting and Handling mode box E -->
    
    <! -- Exception handling mode box S -->
    <el-dialog...
    </el-dialog>
    <! -- Exception handling mode box E -->
    
    <! Modal box S -->
    <el-dialog...
    </el-dialog>
    <! -- Add supplementary remarks Mode box E -->
  </div>
</template>
Copy the code

As you can see from optimizing the code above, I have added a comment to divide the HTML code section according to the function, and marked the beginning S and the end E. In addition, some logical comments were added where the data fields returned from the back end were assigned (rcv_snd) to prevent developers from getting confused later.

1.2 data

There is also a place for comments, trouble developers all over the world can add… Hello, hello, hello, everybody.

<script lang="ts">
export default class LetterDetail extends Vue {
  private myThis: any = this
  private isLoading: boolean = false // Whether the file is being loaded
  private isYQS: boolean = false // Whether the letter has been received
  private letterDetail: any = {} // Letter details
  
  private isAddRemarkShow: boolean = false // Whether to display the add Remarks mode box
  private remarkForm: any = { // Remarks information
    itemId: ' '.type: 'mail'.remark: ' '
  }
  private remarkList: Array<any> = [] // Remarks list

  private logisticsConstant: Array<any> = [] // Logistics constants
  private logisticsInfo: Array<any> = [] // Logistics information. }Copy the code

Add a business-related single-line comment after each initialization variable and wrap according to the correlation.

1.3 methods

<script lang="ts">
export default class LetterDetail extends Vue {.../* Update letter details */
  private updateLetterDetail(id: string): void{... }/* Withdraw the letter */
  private handleRecallLetter(): void{... }/ * receipt * /
  private handleSign(): void{... }/* Integrate logistics constants and logistics information and update */
  public _getLogistics(logisticsInfo: any): void{... }/* Obtain supplementary remarks */
  private _getRemark(itemId: string, type: string): void {...}
  
  ...
}
Copy the code

Add as many lines of comment as possible to each method and explain its functionality.

Second, the naming

Naming will not stick to the code, I as the ultimate obsessive compulsive disorder, organized a code style guide and keep it in mind. The following directly open a detailed article, of course, from the above part of the code has been posted can also see that naming has its own set of rules and styles.

The suggestion about naming is reference and unity. Refer to the current good component library code style or Vue official website style guide, and make consistent naming rules for context.

Third, the logical

Refactoring reusable components can also start with input attributes, thrown events, and public data.

3.1 Input parameter Properties

Let’s take a look at the internal code of the Prop component before optimization:

<script lang="ts">
export default class LetterDetail extends Vue {
  @PropSync('modal', { type: Boolean })
  syncedModal: Boolean

  @Prop()
  data: any

  @PropSync('info', { type: Array })
  syncedInfo: Array<object>
}
Copy the code

The above Prop declaration is written in Vue + TypeScript. Data (mail details) and INFO (logistics details) are actually retrieved from the same interface, but the data retrieved from the interface needs to be processed and split. I took the data out of the component over a year ago and split it up and passed it to LetterDetail, don’t ask why, ask metaphysics. This code is now very confusing.

Let’s take a look at the optimized component code for Prop:

<script lang="ts">
export default class LetterDetail extends Vue {
  @PropSync('visible', { type: Boolean })
  syncedVisible: Boolean

  @PropSync('id', { type: String })
  syncedId: string

  @Watch('id',  { immediate: true.deep: true })
  onSyncedIdChanged(newVal: string) {
    if (newVal) {
      this.updateLetterDetail(newVal)
    }
  }
}
Copy the code

In the optimized code, we have removed data (letter details) and info (logistics details) and replaced it with ID (letter ID), whose type is a string, and we listen for the ID input attribute. When the ID value exists and changes, we request the interface to get the letter details and update it.

3.2 Throwing Events

Let’s take a look at the internal component code for Emit before optimization:

<script lang="ts">
export default class LetterDetail extends Vue {
  @Emit()
  closeModal(): void {
    this.logisticsInfo = []
    this.cisConstant = []
    this.signerForm.signerId = ' '
    this.signerForm.signerName = ' '
    this.signerForm.signerPathName = ' '
  }

  @Emit()
  updateInfo(): string {
    return this.data.mail_id
  }
}
Copy the code

Saw this piece of code I no speech, why do you want to add is not very good updateInfo thrown, may was due to the details to get letters of external logic into the components, when updated letter status inside the operating components must be within the component rethrow mail id, to get on the outside of the component to mail details update. This is digging a hole and then digging another hole to fill the first hole.

Let’s go straight to the component code optimized for Emit:

<script lang="ts">
export default class LetterDetail extends Vue {
  /* Turn off the modal box notification */
  @Emit('closed')
  closedLetterDetail(): void {
    this.letterDetail = {}
    this.logisticsInfo = []
    this.logisticsConstant = []
    this.signerForm.signerId = ' '
    this.signerForm.signerName = ' '
    this.signerForm.signerPathName = ' '}}Copy the code

The updateInfo event is removed and the closed event is left, because when the letter details modal box is closed, the parent component needs to be notified to update the information corresponding to the parent component, such as in the parent component:

private handleLetterDetailClosed(): void {
  this.isLetterDetailShow = false
  this.mailId = ' '
}
Copy the code

3.3 Public Data

This code is the dumbest:

<script lang="ts">
export default class LetterDetail extends Vue {
  /* Get updated logistics information */
  public _getLogisticsInfo(): void {
    api.getCis().then(res= > {
      this.cisConstant = res.data.data
      this.logisticsInfo = util.deepCopy(this.syncedInfo)
      // ...}}})Copy the code

In the old code, the logistics information info is derived from Prop, but the getCis() here is actually to obtain the logistics information state constant, and then replace the constant field in THE INFO with the data obtained by getCis() into Chinese, which is the final logistics information.

The above code is written, each update needs to get a constant logistics information, I?? I’ll just log in and get most of the constants and save them in store and then pull them out when I need them.

So the updated code, but also incidentally optimized the number of requests! Let’s look at the optimized code:

<script lang="ts">
export default class LetterDetail extends Vue {
  @State('common') stateCommon: any
  
/* Get logistics constant, update logistics information */
  public _getLogistics(logisticsInfo: any): void {
    this.logisticsConstant = this.stateCommon.cisConstant
    this.logisticsInfo = logisticsInfo
    // ...}}Copy the code

Four, the last

These three refactorings do not necessarily optimize code in order. In actual reconstruction scenarios, annotation optimization and naming optimization focus on practicability, that is, in the process of logical optimization of code, the correctness of logic is mainly guaranteed, and annotation optimization and naming optimization play an auxiliary role. Logical code optimization is made clearer by increasing comments and canonical naming.

It’s Friday, happy fishing!