There are no right or wrong points in this article, and there are certainly some imperfections. It combines my daily development and experience. It helps you write code with more rigor, and hopefully it helps after you’ve read it. It takes about half an hour to read this article.

1. The comments

(1) Comments at the top of the file, including description, author, date

/** * @description xxxxxx * @author chengfeng * @since 19/05/21 */
Copy the code

(2) Comments of the module

/** * Copy data * @param {*} data Source data to be copied * @param {Boolean} [isDeep=false] Whether a deep copy is made. The default is shallow copy * @return {*} Returns the copied data */
Copy the code

(3) Business code comment

/* Business code comments */
Copy the code

(4) Variable annotation

interface IState {
  / / name
  name: string;
  / / phone
  phone: number;
  / / address
  address: string;
}
Copy the code

2. Reference component order

  • Reference to the external component libraries, then to the current component block-level components, then to the common function libraries in Common, and then to the CSS styles
import * as React from 'react';
import { Dropdown, Menu, Icon } from 'antd';
import Header from './Header';
import toast from 'common/toast';
import './index.less';
Copy the code

3. The quotation

  • Use single quotes, or es6 backquotes

4. The indentation

  • Use two Spaces
const handleCheck = (a)= > {
  onCancel && onCancel();
  onClose && onClose();
};
Copy the code

5. A semicolon

  • Every expression except the code block must be followed by a semicolon.

6. The brackets

The following keywords must be followed by braces (even if the block contains only one line) : if, else, for, while, do, switch, try, catch, finally, with.

// not good
if (condition) doSomething();

// good
if (condition) {
  doSomething();
}
Copy the code

7. The blank space

  • Binary and ternary operators must have a space on either side, and unary operators are not allowed to have a space between them and the object they operate on.
// bad ++ x; y ++; z = x? 1:2; // good ++x; y++; z = x ? 1:2;Copy the code
  • The open curly brace {used as the start of a code block must be preceded by a space.
// bad
if (condition){
}

while (condition){
}

function funcName(){
}

// good
if (condition) {
}

while (condition) {
}

function funcName() {}Copy the code
  • If/else/for/while/function/switch/do/try/catch/finally keyword must be followed by a space.
// bad
if(condition) {
}

while(condition) {
}

(function() {
})();

// good
if (condition) {
}

while (condition) {
}

(function () {
})();
Copy the code
  • When an object is created, the: attribute must be followed by a space, and no space is allowed before the: attribute.
// bad
var obj = {
    a : 1,
    b:2,
    c :3
};

// good
var obj = {
    a: 1,
    b: 2,
    c: 3
};
Copy the code

8. A line break

  • Each individual statement must end with a newline.
  • In function declaration, function expression, function call, object creation, array creation, for statement and other scenarios, do not allow in, or; Before the line break
// bad
var obj = {
    a: 1
    , b: 2
    , c: 3,
};

function test() {... }for (const key in object)
 {
  if (object.hasOwnProperty(key)) {
    const element = object[key];

  }
}
// good
var obj = {
    a: 1,
    b: 2,
    c: 3,
};

function test() {... }for (const key in object) {
  if(object.hasOwnProperty(key)) { const element = object[key]; }}Copy the code
  • No line feeds are required after the following keywords: else, catch, finally
// bad
if (condition) {
    ...
}
else{... } try { ... } catch (e) { ... } finally { ... } // goodif (condition) {
    ...
} else{... } try { ... } catch (e) { ... } finally { ... }Copy the code

9. Arrays, objects

  • Object attribute names do not need to be quoted;
  • Objects should be indented, not on one line.
  • Do not have a comma at the end of the array.
  • The object must end with a comma.

// bad
const a = {
    'b': 1}; const a = {b: 1}; const a = { b: 1, c: 2 }; const arr = [1, 2, 3, 4,]; // good const a = { b: 1, c: 2, }; const arr = [1, 2, 3, 4];Copy the code

Named after 10.

  • Class name: big hump style, letters and numbers, for example: AbcTest. No Chinese characters, no special symbols, no non-hump style.

  • Function name: small hump style, letters and numbers, for example: abcTest. Ban Chinese characters, special symbols, and non-hump styles such as snake_case.

  • Variable name: Same as function name.

  • Constants: All capital letters, numbers, and underscores (_), words separated by underscores (_), for example, ABC_TEST. Chinese characters, special symbols, and lowercase letters are prohibited.

  • Use the onXxx form as the name of the attribute used for the callback in props.

interface IProps { onClose? :(a)= > void; onOk? :(item: Record<string, any>) = > void;
}
Copy the code
  • Event functions within a component start with handle and end with handleCheckBtn.
  • Use a word of the form withXxx for the name of the higher-order component.
  • The name of an interface is preceded by I for interface
interface IProps {}
interface IState {}
Copy the code

11. Type assertion

// bad
function getLength(something: string | number): number {
    return something.length;
}

// index.ts(2,22): error TS2339: Property 'length' does not exist on type 'string | number'.
//   Property 'length' does not exist on type 'number'.

// bad 
function getLength(something: string | number): number {
    if ((<string>something).length) {
        return (<string>something).length;
    } else {
        return something.toString().length;
    }
}

// good
function getLength(something: string | number): number {
  if (typeof something === 'string') {
    return something.length;
  } else {
    returnsomething.toString().length; }}Copy the code

12. Interface declaration order

The daily use is more than four, read-only parameters put the first, the second mandatory parameters, optional parameters, uncertain parameters put the last

interface iProps {
  readonly x: number;
  readonlyy: number; name: string; age: number; height? : number; [propName: string]: any; }Copy the code

13. Ts useful related tools generics

  • Record

    uses this to declare the type of the object structure
    ,any>
Const people:Record<string,any> = {name: Record<string,any> = {name:'chengfeng',
    age: 10
}
Copy the code
  • The Partial function makes the properties passed in optional.
interface iPeople {
    title: string;
    name: string;
}

const people: Partial<iPeople> = {
    title: 'Delete inactive users'}; The structure defined can be any key of the interface iPeopleCopy the code
  • The Readonly function is to make the passed property read-only
interface iPeople {
    title: string;
    name: string;
}

const people: Readonly<Todo> = {
    title: 'todo list', name: chenfeng; }; The title name attribute is now read-onlyCopy the code
  • Required is used to make the attributes passed in mandatory
interface iPeople { title? : string; name? : string; } const people1: Props = { title:'ts' }; // OK

const people22: Required<iPeople> = { title: 'ts' }; // Error: property 'name' missing
Copy the code

To view more

14. Ts Some useful tips

  • keyof
interface iPeople {
  name: string;
  age: number
}

type T = keyof iPeople // -> "name" | "age"
Copy the code
  • in
type Keys = "a" | "b"
type Obj =  {
  [p in Keys]: any
} // -> { a: any, b: any }
Copy the code

15. Standardize others

  • Do not use var to declare variables
  • Variables that will not be modified are declared const
  • Removes code that is declared but not referenced
  • Disable debug in your code
  • Empty code blocks are not allowed

16. Put the state declaration in the constructor only if the initial state needs to be calculated from props. Otherwise, use a static property to declare the state, and generally don’t pass the prop to state.

// bad
constructor() {this.setState({ people: this.props.people })
}

// good
state: IState = {
  people: {}};Copy the code

17. Render default values

  • Adding a non-null judgment can improve the robustness of your code. For example, some values returned by the back end may not exist and should be given default values.
// bad
render(){
  {name}
}

// goodrender(){ {!! name ||The '-'}}Copy the code
  • There is another case where the back end should return an array to you, but the database can’t get the data, so maybe the back end returns null, and the front end null.length. So gg
// bad
const { list, totalCount } = awaitgetPeopleList(keyword, page, pageSize); The list could benullorundefinedList. Length will directly cause the front end to report an errorthis.setState({
  status: STATUS.READY,
  apps: list,
  total: totalCount,
  page: page,
});


// good 
const { list, totalCount } = await getPeopleList(keyword, page, pageSize);
this.setState({
  status: STATUS.READY,
  apps: list || [],
  total: totalCount || 0.page: page,
});

Copy the code

18. Uncertain properties, but finally crazy use… Access nonexistent properties

For example, in some places, if you are not sure what is in this variable, but you think it is, you are crazy. Datalist.foreach () data.datalist. ForEach () data.datalist. ForEach ()

// bad
const data = await getPeopleList(keyword, page, pageSize);
data.dataList.forEach() // Hang up

// good
const data = await getPeopleList(keyword, page, pageSize);
if (data && data.dataList && Array.isArray(data.dataList) {
    data.dataList.forEach() 
}
Copy the code

19. Data format conversion

  1. A + sign is used to convert a string to an integer
let maxPrice = +form.maxPrice.value;
let maxPrice = Number(form.maxPrice.value);
Copy the code
  1. Convert to a Boolean value!!
letmobile = !! ua.match(/iPhone|iPad|Android|iPod|Windows Phone/);
Copy the code

20. Determine whether the conditions are true or false

In js, the following is false, and the other cases are true

  • false
  • null
  • undefined
  • 0
  • “(empty string)
  • NaN

21. Simple components can be replaced with functions

// bad
class Listing extends React.Component {
  render() {
    return <div>{this.props.hello}</div>; }}// good
function Listing({ hello }) {
  return <div>{hello}</div>;
}
Copy the code

22. Cache commonly used attributes

// bad
this.props.app.openid;
this.state.time

// good
const { app } = this.props;
const { time } = this.state;
console.log(app.openid)
Copy the code

23. Use trim() for input

// bad
let searchContent = form.search.value;

// good
let searchContent = form.search.value.trim();
Copy the code

24. Escape before using location to jump

// bad
window.location.href = redirectUrl + '? a=10&b=20';

// good
window.location.href = redirectUrl + encodeURIComponent('? a=10&b=20');
Copy the code

25. Use the react – the router


// bad
import { withRouter, RouteComponentProps } from 'react-router-dom';

export interface IProps extends RouteComponentProps<any> {}
class App extends React.Component<IProps.AppStates> {}
export default withRouter(App);


// good
import { withRouter, RouteComponentProps } from 'react-router-dom';

class App extends React.Component<IProps & RouteComponentProps<{}>, AppStates> {}
export default withRouter(App);

Copy the code

26. At the same time, develop the data request API directory Git conflict directory scheme

  • Create a new directory under the API directory, which corresponds to the level 1 TAB, and put an index.js inside this directory. Finally, import all API requests used by the level 2 TAB components into this index.js directory.
/ / now. | | - API - pageA ts | - pageB. Ts / / advice | | - API - pageA | - index. Js | - aaa. Js | - BBB. Js | - pageB | - index. Js | - aaa.js |- bbb.js |- ccc.jsCopy the code

27. Components are nested too deep

  • Generally, there are no more than three or four layers of components. Too many layers may lead to too much data transmission. When you do some fine-grained operations, it may be complicated to deal with.

28. Code filters out situations you haven’t considered

  • For example, if you only want to manipulate strings for a function, you must allow only strings at the beginning of the function
function parse (str:string){
  if (typeof(str) === 'string') {}}Copy the code

29. Asynchronous requests in business code need a try catch

  • Ajax request, try catch, error message back end return, and do some failed state operation like go to the list page, we need to have a loading state, and then request the data, but if it fails, We also need to remove the loading state and write the loading hidden code in finally.
getStudentList = async() = > {try {
    this.setState({
      loading: true.isEmpty: false
    });
    await getStudentList({});
  } catch (e) {
    // TODO
    console.log(e)
  } finally {
    // Some backstop operations after failure
    this.setState({
      loading: false.isEmpty: true}); }};Copy the code

30. There are three ways to use setState

// Object this.setstate ({}) // function, usually used insetThis.setstate (() => {// TODO console.log()' ')
    return{a:300}}) // The second argument is usually used insetThis.setstate ({a:300}, () => {// TODO})Copy the code

31. SetState may be synchronous

  • SetState is “asynchronous” in react synthetic events and hook functions.
  • SetState is synchronized between native events and setTimeout.

32. Do not add await before setState

  • SetState can also be preceded by await, which makes it a synchronous setting state, but this is a coincidence, and it is not certain that future versions will not support it. In order to follow the design principles of the React framework, we use the form of callback functions.
// bad
func = async (name, value, status) => {
  await this.setState({
    name
  });
  // TODO
};

// good
func = (name, value, status) = > {
  this.setState(
    {
      name
    },
    () => {
      // TODO}); };Copy the code

33. Prevent event default behavior

  • In React you cannot prevent the default behavior by returning false. PreventDefault must be explicitly called.

34. Remove side effects from componentWillUnmount

  • Remove EventListener
  • Abort data request
  • Clearing timer

35. key

  • Optimize the key in the component to maximize dom reuse
//bad
this.state.dataAry.map((item, index) = > {
  return <span key={index} />;
});

//good
this.state.dataAry.map(item => <span key={item.id} />);
Copy the code

36. Must have hasOwnProperty judgment in for-in (disallow reading properties of prototype objects directly)

//bad
const arr = [];
const key = ' ';

for (key in obj) {
  arr.push(obj[key]);
}

//good
const arr = [];
const key = ' ';

for (key in obj) {
  if(obj.hasOwnProperty(key)) { arr.push(obj[key]); }}Copy the code

37. Use of third-party library functions

  • Use try catch package, prevent the third party library error, resulting in the entire program crash
/* * Echart is used for scheming, but it can affect the execution of business code when its own errors occur */
// bad
const iniDom = document.getElementById('init-container');
const echartObj = echarts.init(iniDom);
this.setState(
  {
    echartObj
  },
  () => {
    const { echartObj } = this.state;
    // Update the chart
    echartObj.setOption(CHART_CONFIG, true); });// good
try {
  const iniDom = document.getElementById('init-container');
  const echartObj = echarts.init(iniDom);
  this.setState(
    {
      echartObj
    },
    () => {
      const { echartObj } = this.state;
      // Update the chart
      echartObj.setOption(CHART_CONFIG, true); }); }catch (error) {
  // TODO
}
Copy the code

38. Prevent XSS attacks

  • Input, Textarea and other tags, do not directly render HTML text on the page, use XSSB filter and output to the tag;
import { html2text } from 'xss';
render(){
  <div
  dangerouslySetInnerHTML={{
    __html: html2text(htmlContent)
  }}
/>
}
Copy the code

39. Get the real DOM from the component

  • Use the createRef() function after version 16
class MyComponent extends React.Component<iProps.iState> {
  constructor(props) {
    super(props);
    this.inputRef = React.createRef();
  }

  render() {
    return <input type="text" ref={this.inputRef} />; } componentDidMount() { this.inputRef.current.focus(); }}Copy the code

40. Reduce the magic number

  • When writing code, try to reduce the number of unknown meanings and try to use English words. For example, when type === 0, I do some operations, so I don’t know why.
// bad
if(type ! = =0) {
  // TODO
}

// good
const STATUS: Record<string, any> = {
  READY: 0.FETCHING: 1.FAILED: 2
};

if (type === STATUS.READY) {
  // TODO
}

// best
enum STATUS {
  / / ready
  READY = 0./ / request
  FETCHING = 1.// The request failed
  FAILED = 2,}Copy the code

41. If you need to optimize React performance (usually not)

  • If the Component’s state and props are simple types, you can inherit PureComponent instead of Component
import { Component, PureComponent } from 'react';
// bad
class Message extends Component {
  render() {
    return <span>{this.state.message}</span>; }}// good
class Message extends PureComponent {
  render() {
    return <span>{this.state.message}</span>; }}Copy the code
  • Rewrite shouldComponentUpdate method, according to the state in shouldComponentUpdate, props have changed to determine whether to need to apply colours to a drawing. There is no need to override the shouldComponentUpdate method if the component inherits from PureComponent
import { isReactPropsEqual, isReactStateEqual } from '@fe/common/lib/equal';
shouldComponentUpdate(nextProps:IProps, nextState:IState) {
    if (isReactStateEqual(nextState,this.state) && isReactPropsEqual(nextProps,this.props)) {
        return false;
    }
    return true;
}
Copy the code

42. Event Indicates the type of the Event object

The Event object type is:

ClipboardEvent<T = Element> ClipboardEvent object

DragEvent<T = Element> Drag and drop the event object

ChangeEvent<T = Element> Change event object

KeyboardEvent<T = Element> KeyboardEvent object

MouseEvent<T = Element> MouseEvent object

TouchEvent<T = Element> Touches the event object

WheelEvent<T = Element> scroll WheelEvent object

AnimationEvent<T = Element> AnimationEvent object

TransitionEvent<T = Element> TransitionEvent object

import { MouseEvent } from 'react';

interface IProps {
  onClick(event: MouseEvent<HTMLDivElement>): void;
}
Copy the code

43. Use private attributes instead of state

For some state properties that don’t need to control the UI, we can just tie it to this, which is a private property, but we don’t need to tie it to this. State, because it will trigger the rendering mechanism and cause a waste of performance. For example, when we ask for paging data, we’ll have a variable.

// bad
state: IState = {
  pageNo:1,
  pageSize:10
};

// good 
queryParams:Record<string,any> = {
  pageNo:1,
  pageSize:10
}
Copy the code

44. Code fine-grained thinking

Sum up in four sentences. When we write components or functions, we separate utility functions from business logic, form checksum from business, event functions from business, and Ajax from business. For example, some pages are redirected via location.href, and some of our business logic is put in didmountMount, but later to change the requirements, may need to use React-Router to redirect, may need to change a lot of logic, so the function is taken out, demand update less code to change. If you’re not sure how to divide the fine-grained functions, I have a suggestion. Detach components or functions from code that has been used more than twice

45. If else and so on too much judgment, late maintenance is difficult.

Personally, if else nesting deep looks not too uncomfortable, uncomfortable is, after the project iteration for a long time, I have forgotten to write the code, and many types or not sure what type, whether will be added later, it is very complicated to change, and it is easy to step the pit and blame. Instead of nesting if with a config, you probably pull out a config.ts and put some config in it.

For example, in your business code, the code will perform different logic depending on the URL parameter.type=wechat&uid=123456&
const qsObj = qs(window.location.url)
const urlType = qsObj.type
// bad 
if (urlType === 'wechat') {
    doSomeThing()
} else if () {
    doSomeThing()
} else if () {
    doSomeThing()
} else if () {
    doSomeThing()
}

// good 
config.t
const urlTypeConfig: Record<string, typeItem> = {
  'wechat': {// key is the correspondingtype
    name: 'wechat', 
    show: ['header'.'footer'.'wechat'] // Shows what might be asynchronous pession: ['admin'], // what is the permission, may be asynchronous},'zhifubao': {// key is the correspondingtype
    name: 'zhifubao', 
    show: ['header'.'footer'.'zhifubao'] // Shows what might be asynchronous pession: ['admin'], // what is the permission, May be asynchronous}, } // Const qsObj = qs(window.location.url) const urlType = qsobj.type object.keys (urlTypeConfig).foreach (item => {if(urlType === item.type) {
    doSomeThing(item.show)
  }
})

Copy the code

46. Do not use renderXXX, use functional components

In order to reduce the amount of code in the render function, some team members will split some elements into the function.

// bad
  renderHeader = () => {
    return (<div />)
  }
  renderBody = () => {
    return (<div />)
  }
  renderFooter = () => {
    return (<div />)
  }
  render() {return(
      <div>
        renderHeader()
        renderBody()
        renderFooter()
      </div>
    )
  }
Copy the code

A better approach is to use functional components instead of writing methods in the current component

// good
 function RenderHeader(props) =  {
    return (<div />)
  }
 function RenderBody(props) =  {
    return (<div />)
  }
 function RenderFooter(props) =  {
    return (<div />)
  }
class Component extends React.Component<iProps, iState>{  
  render () {
    return(
      <div>
        <RenderHeader />
        <RenderBody />
        <RenderFooter />
      </div>
    )
  }
}
Copy the code

47. A Label safety problem

Security issues during opening a new window using the A TAB. You can use window.opener to control the original page from the new page. If the old and new pages are in the same domain, you can do whatever you want with the original page in the new page. If the domain is different, the new page can still access the location object of the original page through window.opener. Location

In the a tag with target=”_blank”, add the rel=”noopener” attribute. If you open the page using window.open, leave the opener object empty.

var newWindow = window.open();
newWindow.opener = null;
Copy the code

Void 0 instead of undefined

clearSessioin = () => {
	
  req.session.userName = undefined;
  
  req.session.userName = void 0
}
Copy the code

49. Do not operate cookies on the front end

When performing front-end and back-end authentication, the domain, Secure, and Httponly modes should be enabled on the back-end to prevent the front-end cookie operation to prevent CSRF attacks.

50. Code check plug-ins

We can use the build tool to inherit husky esLint TSLint -stage prettier to regulate code.

  • eslint-config-prettier
  • eslint-plugin-prettier
  • eslint-plugin-react
  • tslint-react
  • tslint-plugin-prettier
  • tslint-config-prettier
  • Team development workflow

reference

  • airbnb
  • Imweb code specification
  • How to painlessly reduce the if else noodle code complexity
  • Do you really understand setState?