Angular best practices

As one of the three front-end frameworks, the Angular framework has its unique advantages and can be used to create efficient, complex, and sophisticated single-page applications. This article introduces the eighteen best practices and examples recommended in the development process of Angular for reference in the development process. 1. trackByWhat When using the * ngFor command to display the array in html, add the trackBy () function, the purpose is to specify an independent idWhy for each item. Under normal circumstances, when there is a change in the array, Angular will The DOM tree is re-rendered. If the trackBy method is added, Angular will know the specific changed elements and refresh the DOM of this specific element to improve the rendering performance of the page.-> NetanelBasalExample 【Before】 <li * ngFor = “let item of items; ”> {{Item}} Copy the code 【After】 // in the template

// in the component
trackByFn (index, item) {
return item.id; // unique id corresponding to the item
} Copy the code 2. When const vs letWhat declare a constant, use const instead of letWhya. Make the assignment intention more clear b. If the constant is reassigned, the compiler will report an error directly to avoid potential risks. C. Increase code readability Example [Before] let car = 'ludicrous car';
let myCar = My ${car};
let yourCar = Your ${car}; if (iHaveMoreThanOneCar) { myCar =KaTeX parse error: Expected 'EOF', got '}' at position 12: {myCar} s`;} ̲ if (youHaveMor… {youCar} s ; }复制代码【After】// 变量car不会被重赋值,所以用const声明 const car = 'ludicrous car'; let myCar =My $ {car} ; let yourCar =Your KaTeX parse error: Expected '}', got 'EOF' at end of input:…) { myCar = ` {myCar} s ; } if (youHaveMoreThanOneCar) { yourCar =$ {youCar} s`;
} Copy the code 3. When using the RxJs operator with the pipeable operator What, use the pipeable operator symbol-> Further reading Whya. Can be optimized by shaking the tree: in the imported code, Only those that need to be executed will be introduced b. It is easy to locate unused operators in the code. Note: Requires RxJs version 5.5 and above Example [Before] import 'rxjs / add / operator / map';
import ‘rxjs/add/operator/take’;

iAmAnObservable
.map(value => value.item)
.take(1)复制代码【After】import { map, take } from ‘rxjs/operators’;

iAmAnObservable
.pipe (
map (value => value.item),
take (1)
) Copy code 4. Isolate API attacks What is not all APIs are safe- > In many cases additional code logic needs to be added to fight for the API The patch is better than putting the logic in the component. It is better to encapsulate it in a separate place: for example, encapsulate it in a service, and then refer to Whya elsewhere. Isolation attacks make the attacks closer to the original request location b. Reduce the code used to deal with attack patching c. Encapsulate these attacks in the same place, easier to find d. When you want to solve the bug, you only need to search in the same file, it is easier to locate Note: also You can make your own tags, such as API_FIX, similar to TODO tags, used to mark API fixes. 5. Template subscription What is best to change in html subscription, not in ts Whya. Async pipeline can automatically unsubscribe: by reducing manual Subscription management can simplify the code b. Reduce the risk of forgetting to cancel the subscription in ts, causing memory leaks (this risk can also be avoided by lint rule detection) c. Reduce the number of subscriptions If the data is changed after reading, and the bug is introduced Example 【Before】 // template

{{ textToDisplay }}

// component
iAmAnObservable
.pipe(
map(value => value.item),
takeUntil(this._destroyed$)
)
.subscribe(item => this.textToDisplay = item复制代码【After】// template

{{ textToDisplay$ | async }}

// component
this.textToDisplay $ = iAmAnObservable
.pipe (
map (value => value.item)
) Copy the code 6. Subscription cleanup If you subscribe to observable, remember to properly cancel the subscription Whya through the take, takeUntil and other operators. If not cancel Subscription may lead to even if the component is destroyed or the user goes to another page, but observe the observable stream is always maintained and cause memory leaks. B. A better approach is to avoid Example [Before] iAmAnObservable
.pipe (
map ( value => value.item)
)
.subscribe (item => this.textToDisplay = item); copy code [After] private _destroyed $ = new Subject ();

public ngOnInit (): void {
iAmAnObservable
.pipe (
map (value => value.item)
// hope to keep listening
until takeUntil (this._destroyed $)
)
.subscribe (item => this.textToDisplay = item);
}

public ngOnDestroy (): void {
this._destroyed . n e x t ( ) ; t h i s . d e s t r The and e d .next(); this._destroyed .complete ();
} Copy the code If you only want the first value, then use a take (1) iAmAnObservable
.pipe (
map (value => value.item),
take ( 1),
takeUntil (this._destroyed $)
)
.subscribe (item => this.textToDisplay = item); Copy the code Note: Here takeUntil and take are used at the same time here, the purpose is to prevent the component has not received the value before it was destroyed, resulting in memory leaks. (If there is no takeUntil, then the subscription will persist until the first value is obtained, and after the component is destroyed, because it is impossible to receive the first value, it will cause a memory leak) 7. Use the appropriate operation For What, select the appropriate merge operator switchMap: when you want to replace the old value with the newly received value mergeMap: when you want to operate on all received values ​​at the same time concatMap: when you want to process the received value in turn exhaustMap : When processing the previous received value, cancel processing of the later value Whya. Compared to using multiple operators in a chain, using a suitable operator to achieve the same purpose helps to effectively reduce the amount of code b. No Proper use of operators may lead to unexpected behavior, because the effects achieved by different operators are different. 8. Lazy loading What if conditions permit, try lazy loading modules in angular applications. Lazy loading refers to loading module content only when needed. Whya. Effectively reduces the volume of applications that need to be loaded. B. By avoiding loading unnecessary modules, it can effectively improve startup performance. Example 【Before】 {path: 'not-lazy- loaded ', component: NotLazyLoadedComponent} 【After】 // app.routing.ts

{
path: ‘lazy-load’,
loadChildren: () => import(lazy-load.module).then(m => m.LazyLoadModule)
}

// lazy-load.module.ts
import { NgModule } from ‘@angular/core’;
import { CommonModule } from ‘@angular/common’;
import { RouterModule } from ‘@angular/router’;
import { LazyLoadComponent } from ‘./lazy-load.component’;

@NgModule ({
imports: [
CommonModule,
RouterModule.forChild ([
{
path: '',
component: LazyLoadComponent
}
]))
],
declarations: [
LazyLoadComponent
]
})
export class LazyModule {} In some cases, you may need to obtain data from multiple observables to achieve a specific purpose. In this case, avoid nesting subscriptions within the subscription block. A better approach is to use the appropriate chain operator. For example: withLatestFrom, combineLatest, etc. Why code odor / readability / complexity: Not completely using RxJs, indicating that developers are not familiar with the shallow use of RxJs API code performance: If it is cold observable, will continue to subscribe to the first observable Until it is complete, then it is to start the work of the second observable. If there is a network request, the performance will be waterfall example [Before] firstObservable KaTeX parse error: Expected '}', got 'EOF' at end of input:… econdObservable .pipe (take (1)) .subscribe (secondValue => {console.log (Combined values are: ${firstValue} &${secondValue}); });});【After】firstObservable . p i p e ( w i t h L a t e s t F r The m ( s e c The n d THE b s e r v a b l e .pipe( withLatestFrom(secondObservable ), first ()) .subscribe (([firstValue, secondValue]) => {console.log (Combined values are: ${firstValue} & ${secondValue});}); 10. Avoid using any, and explicitly define the type What when declaring variables or constants, specify a specific type instead of simply using anyWhya. When declaring an unspecified type in TS In the variable or factory, the type will be inferred from the value assigned, which is likely to cause unexpected problems. A classic example is as follows: Example [Before] const x = 1; const y = 'a'; const z = x + y; console.log (Value of z is: ${z}// Output Value of z is 1a. If the original expected input is y is also a numeric type, it will cause unexpected problems. [After] These problems can be avoided by specifying an appropriate type for the declared variable: const x: number = 1; const y: number = 'a'; const z: number = x + y; // This input will cause Compilation error throws Type '"a"' is not assignable to type 'number'. Cons y: number Through the above method, you can avoid bugs caused by missing types. Another benefit of specifying types is that it can make refactoring easier. More secure Example 【Before】 public ngOnInit (): void {let myFlashObject = {name: 'My cool name', age: 'My cool age', loc: 'My cool location'} this.processObject (myFlashObject);} public processObject (myObject: any): void {console.log ( Name: ${myObject.name}); console.log ( Age: ${myObject.age}); console.log (Location: ${myObject.loc});) // Output Name: My cool nameAge: My cool ageLocation: My cool location If you want to rename the loc property name in myFlashObject locationpublic ngOnInit (): void {let myFlashObject = {name: 'My cool name', age : 'My cool age', location: 'My cool location'} this.processObject (myFlashObject);} public processObject (myObject: any): void {console.log ( Name: ${myObject.name}); console.log ( Age: ${myObject.age}); console.log (Location: ${myObject.loc});} // Output Name: My cool nameAge: My cool ageLocation: undefined When the type is not specified for myFlashObject, it seems that the method loc attribute does not exist in myFlashObject instead of the above result caused by the wrong value of the attribute [After] when the right MyFlashObject adds a type definition, we will get a clearer compilation error problem as follows type FlashObject = {name: string, age: string, location: string} public ngOnInit (): void {let myFlashObject: FlashObject = {name: ' My cool name ', age:' My cool age ', // Compilation error Type' {name: string; age: string; loc: string;} 'is not assignable to type' FlashObjectType '. Object literal may only specify known properties , and 'loc' does not exist in type 'FlashObjectType'. loc: 'My cool location'} this.processObject (myFlashObject);} public processObject (myObject: FlashObject): void {console.log ( Name: ${myObject.name}); console.log ( Age: ${myObject.age}) // Compilation error Property 'loc' does not exist on type 'FlashObjectType'. Console.log (Location: ${myObject.loc});} If you are starting a brand new project, it is recommended to set strict: true mode in the tsconfig.json file to turn on strict mode and turn on all strict type checking options 11. Use lint rules Whatlint rules consist of multiple presets Options such as no-any, no-magic-numbers, no-consle, etc., you can turn on specific verification rules in your tslint.json file. Why using lint rules means that there should not be generated somewhere When the behavior occurs, you will get a clearer error. This will improve the consistency and readability of your application code. Some lint rules even have specific fix solutions for solving this lint task. If you want to define your own lint rules, you can also write a classic example of using TSQuery to write your own lint rules. A classic example is as follows: Example [Before] public ngOnInit (): void {console.log ('I am a naughty console log message') ; console.warn ('I am a naughty console warning message'); console.error ('I am a naughty console error message');} // The output does not report an error, but is in control The following information is printed in: I am a naughty console message I am a naughty console warning message I am a naughty console error message [After] // tslint.json {“rules”: {… “no-console”: [true, “log” , // no console.log allowed “warn” // no console.warn allowed]}} //… component.tspublic ngOnInit (): void {console. log ('I am a naughty console log message'); console.warn ('I am a naughty console warning message'); console.error ('I am a naughty console error message');} // Outputlint is in the console. Errors are reported in the log and log.warn statements, and console.error will not be reported, because Calls to 'console.log' are not allowed. Calls to 'console.warn' are not allowed. l. Reusable component What extracts reusable code snippets from the component into a new component to make the component "dumb" as much as possible, so that it can be reused in more scenarios to write "dumb" components means that there is no hidden Contains special logic. The operation simply relies on the input and output provided to it as a general rule. The component with the most child node in the component tree will be the most "dumb" Why reusable component Reduce the code repetition rate, which makes it easier to maintain and change the dumb component is simpler, so the possibility of bugs is also lower. The dumb component allows you to carefully think about how to extract the common component API and help you identify mixed problems. 13. The component only handles display logic. What to avoid encapsulating business logic other than display logic into the component, ensuring that the component is only used to handle display logic Whya. Components are designed to control views and display purposes. Any business logic should be encapsulated in its own appropriate method or service, and business logic should be separated from component logic. B. If business logic is extracted into a service, it is usually more Suitable for using unit tests, and can be reused by other components that require the same business logic 14. Avoid long methods What long methods usually indicate that they already contain too many tasks, try to use the single responsibility principle One method should be completed as a whole One thing, if there are multiple operations, then we can extract these methods to form independent functions, so that they are solely responsible for their responsibilities, and then call them Whya. The long method is difficult to read, understand, and maintain. They are prone to bugs, because changing some of them is likely to affect other logic within the method. This also makes code refactoring more difficult. B. Methods can be measured by cyclomatic complexity. There are some TSLint methods for detecting cyclomatic complexity. You can use them in your project to avoid bugs and detect code availability. 15. DryWhatDry = Do not Repeat Yourself guarantees that there is no duplicate code in the code warehouse, extract the duplicate code, and refer to where it needs to be used. Whya. Using duplicate code in multiple places means that if we want to change the code logic, we need Modifying in multiple places, reducing the maintainability of the code makes it difficult to make changes to the code logic and the testing process is very long b. Extracting duplicate code to one place means that only one code needs to be modified and a single test c . At the same time, less code means faster speed. 16. Increase the cache What response to initiate API requests usually does not change often, in such scenarios, you can increase the cache mechanism and store the obtained value as the same API request When re-launching, confirm whether there is already a value in the cache, if so, it can be used directly, otherwise Initiate the request and cache. If these values ​​will change but change infrequently, then a cache time can be introduced for deciding whether to use the cache or to call again. Why has a cache mechanism means that unnecessary API calls can be avoided, which helps improve the application by avoiding repeated calls Responsiveness, no longer need to wait for the network to return, and we do not need to download the same information repeatedly. 17. Avoid logic in the template. If you need to add any logic in the HTML, even if it is just a simple &&, it is best to extract it to The logic in the Why template within the component is difficult to unit test. When switching the template code, it is easy to cause code problems [Before] // template <p * ngIf = "role === developer '"> Status: Developer DryWhatDry = Do not Repeat Yourself to ensure that there is no duplicate code in the code warehouse, extract the duplicate code, and reference it where needed. Whya. Using duplicate code in multiple places means that if we want to change the code logic, We need to modify in multiple places, which reduces the maintainability of the code and makes it difficult to change the code logic and the testing process is very long. B. Extracting duplicate code to one place means that only one code needs to be modified and a single time Test c. At the same time, less code means faster speed. 16. Increase the cache. What initiated the API request response is usually not often changed, in such scenarios, you can increase the cache mechanism and store the obtained value as the same When the API request is re-initiated, confirm whether there is already a value in the cache, and if so, it can be used directly, otherwise the request is initiated and cached. If these values ​​will change but change infrequently, then a cache time can be introduced for deciding whether to use the cache or to call again. Why has a cache mechanism means that unnecessary API calls can be avoided, which helps improve the application by avoiding repeated calls Responsiveness, no longer need to wait for the network to return, and we do not need to download the same information repeatedly. 17. Avoid logic in the template. If you need to add any logic in the HTML, even if it is just a simple &&, it is best to extract it to The logic in the Why template within the component is difficult to unit test. When switching the template code, it is easy to cause code problems [Before] // template <p * ngIf = "role === developer '"> Status: Developer DryWhatDry = Do not Repeat Yourself to ensure that there is no duplicate code in the code warehouse, extract the duplicate code, and reference it where needed. Whya. Using duplicate code in multiple places means that if we want to change the code logic, We need to modify in multiple places, which reduces the maintainability of the code and makes it difficult to change the code logic and the testing process is very long. B. Extracting duplicate code to one place means that only one code needs to be modified and a single time Test c. At the same time, less code means faster speed. 16. Increase the cache. What initiated the API request response is usually not often changed, in such scenarios, you can increase the cache mechanism and store the obtained value as the same When the API request is re-initiated, confirm whether there is already a value in the cache, and if so, it can be used directly, otherwise the request is initiated and cached. If these values ​​will change but change infrequently, then a cache time can be introduced for deciding whether to use the cache or to call again. Why has a cache mechanism means that unnecessary API calls can be avoided, which helps improve the application by avoiding repeated calls Responsiveness, no longer need to wait for the network to return, and we do not need to download the same information repeatedly. 17. Avoid logic in the template. If you need to add any logic in the HTML, even if it is just a simple &&, it is best to extract it to The logic in the Why template within the component is difficult to unit test. When switching the template code, it is easy to cause code problems [Before] // template <p * ngIf = "role === developer '"> Status: Developer Adding a cache What response to an API request usually does not change often. In such scenarios, you can increase the cache mechanism and store the obtained value. When the same API request is re-initiated, confirm whether there is already a value in the cache. If yes, it can be used directly, otherwise it will initiate the request and cache. If these values ​​will change but change infrequently, then a cache time can be introduced for deciding whether to use the cache or to call again. Why has a cache mechanism means that unnecessary API calls can be avoided, which helps improve the application by avoiding repeated calls Responsiveness, no longer need to wait for the network to return, and we do not need to download the same information repeatedly. 17. Avoid logic in the template. If you need to add any logic in the HTML, even if it is just a simple &&, it is best to extract it to The logic in the Why template within the component is difficult to unit test. When switching the template code, it is easy to cause code problems [Before] // template <p * ngIf = "role === developer '"> Status: Developer Adding a cache What response to an API request usually does not change often. In such scenarios, you can increase the cache mechanism and store the obtained value. When the same API request is re-initiated, confirm whether there is already a value in the cache. If yes, it can be used directly, otherwise it will initiate the request and cache. If these values ​​will change but change infrequently, then a cache time can be introduced for deciding whether to use the cache or to call again. Why has a cache mechanism means that unnecessary API calls can be avoided, which helps improve the application by avoiding repeated calls Responsiveness, no longer need to wait for the network to return, and we do not need to download the same information repeatedly. 17. Avoid logic in the template. If you need to add any logic in the HTML, even if it is just a simple &&, it is best to extract it to The logic in the Why template within the component is difficult to unit test. When switching the template code, it is easy to cause code problems [Before] // template <p * ngIf = "role === developer '"> Status: Developer

// componentpublic ngOnInit (): void {this.role = 'developer';} 【After】 <p * ngIf = “showDeveloperStatus”> Status: Developer // componentpublic ngOnInit (): void {this.role = 'developer'; this.showDeveloperStatus = true;} 18. Safely declare the string type What If there are some string variables with only certain values, it is better to declare it as a possible value collection type than to declare it as a string type Why By providing proper declaration of variables, it helps to avoid bugs: when writing code exceeds expectations, it can be found at the compilation stage, rather than waiting to be run to find [Before] private myStringValue: string;

if (itShouldHaveFirstValue) {
myStringValue = ‘First’;
} else {
myStringValue = ‘Second’
}复制代码【After】private myStringValue: ‘First’ | ‘Second’;

if (itShouldHaveFirstValue) {
myStringValue = ‘First’;
} else {
myStringValue = ‘Other’
}

// This will give the below error
Type ‘“Other”’ is not assignable to type ‘“First” | “Second”’
(property) AppComponent.myValue: “First” | “Second”

Published 28 original articles · Likes0 · Visits 907

Guess you like

Origin blog.csdn.net/srhgsr/article/details/105498961