preface

Although we now have various code detection tools such as ESLint, TSLint, Sonar, etc. However, these tools can only detect some relatively simple code problems at present. For some complex modules and code readability problems, we still need to solve them through people. Only by reaching a unified specification and a certain consensus can such problems be solved to a certain extent.

With that in mind, this leads to today’s topic: React Best Practices (which, of course, is a bit title-agnostic 😂).

Variable article

1. Definition of the number of variables

We rarely restrict the number of variable definitions. However, based on this, variable abuse often occurs, which is very obstructive to later maintenance.

// 👎 export const kpi = 4; Function example() {// use.... return; } // 👍 delete the data if it is not used, otherwise after three months I will not be able to delete, afraid is not where usedCopy the code

2. Name variables

Variable naming in the process of program development is not only a headache, but also a test of the comprehensive quality of developers, which will directly affect the final delivery quality of code and the mental endurance of code Review staff.

In the naming of variables should minimize the occurrence of abbreviations, so as to see the name of the meaning.

// 👎 feel good abbreviation: let fName = 'Jackie '; // It looks like the naming is standard, abbreviations, humps are used, all kinds of tools to check the specification pass ESlint, But, fName is what? What are you doing? let rContent = 'willen'; // 👍 let firstName = 'Jackie '; let rightContent = 'willen';Copy the code

3. Specific variables

Timely annotation of business variables to reduce unstated variables is really important for business understanding!

// 👎 unspecified arguments: Why less than 8? Length, displacement, or height? if (value.length < 8) { .... } // 👍 add a comment const MAX_INPUT_LENGTH = 8; If (value.length < MAX_INPUT_LENGTH) {// The maximum input length cannot be longer than.... }Copy the code

Use declarative variables

In function arguments, avoid using long code; using declarative variables instead greatly increases the readability and maintainability of the code.

// 👎 const address = 'One Infinite Loop, Cupertino 95014'; const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?) \s*(\d{5})? $/; SaveCityZipCode (address.match(cityZipCodeRegex)[1], // Address. Match (cityZipCodeRegex)[2] // See the code yourself); // 👍 const address = 'One Infinite Loop, Cupertino 95014'; const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?) \s*(\d{5})? $/; const [, city, zipCode] = address.match(cityZipCodeRegex) || []; saveCityZipCode(city, zipCode);Copy the code

5. Variable assignment

Effective underpinning of variable assignments is also known as exception handling. In the process of writing need to consider the null, abnormal circumstances of the desired assignment and return value, which is the basic condition of the normal operation of the program.

// 👎 no backstop for evaluated variables const MIN_NAME_LENGTH = 8; let lastName = fullName[1]; If (lastname.length > MIN_NAME_LENGTH) {// Then you have successfully buried a hole in your code. Have you considered the situation if fullName = [' Jackie ']? So the program will explode as soon as it runs. Why don't you try it. . } // 👍 const MIN_NAME_LENGTH = 8; let lastName = fullName[1] || ''; // If fullName[1] is not available, it will not assign undefined, or at least a null character. Basically, the lastName variable type is still String, and all attributes in the String prototype chain can be used without error. It's not going to be undefined. if(lastName.length > MIN_NAME_LENGTH) { .... }Copy the code

function

1. Function naming

4,500 programmers on Quora and Ubuntu Forums have voted on problems they’ve encountered with their programming. Naming functions, variables, etc., was considered the most difficult task by 49% of programmers.

Personally, if you can clearly identify the purpose of a function by looking at its name, and what data it returns, that is the appropriate name.

// 👎 function showFriendsList() {.... } // Do you know if this returns an array, an object, true or false? function emlU(user) { .... } shouldShowFriendsList() {shouldShowFriendsList() {shouldShowFriendsList() {shouldShowFriendsList() {shouldShowFriendsList() {// 👍 } function isEmpty() {... } function canCreateDocuments() {... } function hasLicense() {... } function sendEmailToUser(user) {.... } // At the beginning of the verb, the purpose of the function is obviousCopy the code

2. Functional functions should be pure functions

Pure function is a very important concept in functional programming. Simply put, it means that the return result of a function only depends on its parameters, and there are no side effects in the execution process. We call this function pure function.

Not all functions need to be pure. For example, event handlers that manipulate the DOM are not suitable for pure functions. However, such event handlers can be handled by calling other pure functions to reduce the number of impure functions in the project.

The main reasons for using pure functions are testability and refactoring.

Function plusAbc(a, b,c) {function plusAbc(a, b,c) {function plusAbc(a, b,c) {function plusAbc(a, b,c) {function plusAbc(a, b,c) { var c = fetch('.. /api'); return a+b+c; } // 👍 function plusAbc(a, b,c) {function plusAbc(a, b,c) {function plusAbc(a, b,c) { return a+b+c; }Copy the code

3. Function parameters are passed

For function parameter transmission, the parameter meaning of the function to be called should be clear, which can greatly reduce the problem caused by incorrect parameter location.

// 👎 Upload parameter No Description Page. GetSVG (API, true, false); Page. getSVG({imageApi: API, includePageBackground: // compress: false,})Copy the code

4. Function disassembly

One of the most important rules in software engineering is that a function does a single function, not a function with multiple functions. As functions need to do more, they become harder to write, test, understand, and compose.

When you can pull out a function to do just one action, they will be easier to refactor and your code will be easier to read. If you follow this rule strictly, you will be ahead of many developers.

// 👎 functions are messy, Function sendEmailToClients(clients) {client.foreach (client => {const clientRecord = Database.lookup (client) if (clientRecord.isActive()) {email(client)}})} // 👍 Function SendEmailToActiveClients (clients) {// Separate, ForEach (email)} function isActiveClient(client) {const clientRecord = database.lookup(client) return clientRecord.isActive() }Copy the code

5. Prioritize functional programming

An issue that is often discussed when using functional programming: performance. Do you sacrifice readability for a bit of performance?

My philosophy is that premature optimization is the root of all evil, and that you should prioritize readability, maintainability, and testability over gimnks to improve performance that doesn’t have a significant impact.

// 👎 use the for loop for(I = 1; i <= 10; A [I] = a[I] +1; } // 👍 let b = a.maap (item => ++item)Copy the code

6. Excessive use of if else in functions

Some novice developers are used to using if else when making logical decisions, which is fine when the logic is simple.

However, when the business encounters logical judgment again in the later business change process, I believe that most people will keep the previous code style, nesting if else in if, which is a pit for later maintenance.

// 👎 if else too much if (a === 1) {... } else if (a ===2) { ... } else if (a === 3) { ... } else { ... } // 👍 can replace switch(a) with switch or array {case 1:.... case 2: .... case 3: .... default: .... } Or let handler = { 1: () => {.... }, 2: () => {.... }.3: () => {.... }, default: () => {.... } } handler[a]() || handler['default']()Copy the code

component

1. Favoring functional components

Functional components – They have a simpler syntax, no lifecycle, constructors, etc., and can express the same logic in simpler code with better readability.

Functional components should be the preferred approach unless error boundaries are required.

// 👎 extends React.Component {state = {Counter: 0, } constructor(props) { super(props) this.handleClick = this.handleClick.bind(this) } handleClick() { this.setState({ counter: this.state.counter + 1 }) } render() { return ( <div> <p>counter: {this.state.counter}</p> <button onClick={this.handleclick}>Increment</button> </div>)}} // 👍 Function Counter() {const [Counter, setCounter] = useState(0) handleClick = () => setCounter(counter + 1) return ( <div> <p>counter: {counter}</p> <button onClick={handleClick}>Increment</button> </div> ) }Copy the code

2. Name the component

Always name the component, even if it is exported by default.

This helps us quickly locate errors when reading the error stack trace and using the React development tool.

If the component name is in the file, it is also easier to locate the component at development time.

// 👎 Invalid name export default () => <form>... </form> // 👍 Export default function form () {return <form>... </form> }Copy the code

3. Organize auxiliary functions

Implementations of helper functions that are independent of the component should be moved outside the component. The ideal place is before the component is defined so that the code is readable from top to bottom.

This greatly reduces the amount of interference in the component, leaving only those things that need attention, and making it easier to track errors and extensions with pure function composition logic that only relies on input.

// 👎 avoid nesting functions that should be moved outside the Component function Component({date}) {function parseDate(rawDate) {... } return <div>Date is {parseDate(Date)}</div>} // 👍 } function Component({ date }) { return <div>Date is {parseDate(date)}</div> }Copy the code

4. Component complexity

If a function does too much, extract some logic and call another function. The same goes for components, which should also be broken up into smaller components if they have too much functionality.

If the extracted function is complex, it needs to be extracted according to certain rules and conditions.

Lines of code is not an objective measure, but rather a matter of accountability and abstraction.

5. Code comments

Code comments have always been a headache for many developers, believing that a piece of complex logic with or without comments will make a difference in the reading experience (stop complaining about other people’s code without comments, start with yourself!). .

Function Component(props) {return (<> {/* Do not display ads if users do not subscribe */} {user.subscribed? null : <SubscriptionPlans />} </> ) }Copy the code

6. Use the wrong boundaries

Errors in one component should not cause the entire UI to crash. In rare cases, if a serious error occurs, we want to delete the entire page or redirect. Most of the time, if we just hide certain elements on the page and show the degraded UI, that’s fine.

When there may be multiple try/catch statements in the data processing function, or the data is not handled in a timely manner, we can use error boundaries outside the data processing component to improve the user experience in a timely manner.

function Component() {
  return (
    <Layout>
      <ErrorBoundary>
        <CardWidget />
      </ErrorBoundary>

      <ErrorBoundary>
        <FiltersWidget />
      </ErrorBoundary>

      <div>
        <ErrorBoundary>
          <ProductList />
        </ErrorBoundary>
      </div>
    </Layout>
  )
}
Copy the code

7. Deconstruction Props

In functional components, we usually use props to pass parameters. But when a component is full of repetitive props passes, it loses its meaning.

An important scenario for not deconstructing props is the need to distinguish between what is external state and what is internal state. But in a regular component, there is no distinction between parameters and variables.

// 👎 props function Input(props) {return < Input value={props. Value} onChange={props. Function Component({value, onChange}) {const [state, function Component({value, onChange}) {const [state, setState] = useState('') return <div>... </div> }Copy the code

8. Number of transmitted parameters

How many props a component should receive is a subjective question. The number of props a component has is positively related to its workload. The more props a component receives, the greater its responsibility. A large number of props is a signal that a component is doing too much.

If there are more than five props, it is time to consider whether to split the component. In some cases, this is a sign that a component needs to be refactored.

Note: The more props a component uses, the more reasons it has to re-render.

9. Pass objects instead of underlying data

One way to limit the number of props is to pass an object instead of the underlying data. They can be combined rather than passed as base data.

This also reduces the need for changes if the user acquires additional fields at a later stage.

// 👎 If the values are related, <UserProfile bio={user.bio} name={user.name} email={user.email} subscription={user.email} /> // 👍 <UserProfile user={user} /> <UserProfile user={user} />Copy the code

Avoid nested ternary operators

Ternary operators become hard to read after the first level, and while they may seem to save code space, it’s best to keep the intent clear in your code and keep it readable.

// 👎 And if it does, what about nesting another layer? isSubscribed ? ( <ArticleRecommendations /> ) : isRegistered ? ( <SubscribeCallToAction /> ) : (<RegisterCallToAction />) // 👍 subscribed CallToActionWidget({subscribed, registered }) { if (subscribed) { return <ArticleRecommendations /> } if (registered) { return <SubscribeCallToAction />  } return <RegisterCallToAction /> } function Component() { return ( <CallToActionWidget subscribed={subscribed} registered={registered} /> ) }Copy the code

11. Encapsulate the list component as a standalone component

Traversing a list is a very common situation and is usually done with the map function. However, in a component with many parameters, excessive refinement can reduce the readability of the component.

When data needs to be mapped, it can be encapsulated in its own separate component. The parent component doesn’t need to care about the details, just needs to know that it’s a list.

Function Component({topic, page, articles, onNextPage }) { return ( <div> <h1>{topic}</h1> {articles.map(article => ( <div> <h3>{article.title}</h3> <p>{article.teaser}</p> <img src={article.image} /> </div> ))} <div>You are on page {page}</div> <button OnClick ={onNextPage}>Next</button> </div>)} 👍 Function Component({topic, page, articles, onNextPage }) { return ( <div> <h1>{topic}</h1> <ArticlesList articles={articles} /> <div>You are on page {page}</div> <button onClick={onNextPage}>Next</button> </div> ) }Copy the code

12. Assign default values to component props

One way to specify the default prop value is to append the defaultProps property to the component, which means that the values of the component functions and their parameters are not put together.

When deconstructing props, I prefer to give the default values directly, which makes it easier to read the code from top to bottom without any jump, and to keep the definitions and values together.

Function Component({title, tags, subscribed}) {return <div>... </div> } Component.defaultProps = { title: '', tags: [], subscribed: Function Component({title = ", tags = [], subscribed = false}) {return <div>... </div> }Copy the code

13. Avoid nested rendering functions

When you need to extract a component from a component or logic, do not place it in a function within the same component. A component should have only its own functionality, defined in this way as nested within its parent.

This means that the nested component has access to all of its parent’s state and data. It makes code harder to read (what does this function do between components?).

Move it to its own component, name it, and pass props instead of being in a closure.

Function Component() {function renderHeader() {return <header>... </header>} return <div>{renderHeader()}</div>} // 👍 import header from '@modules/common/components/Header' function Component() { return ( <div> <Header /> </div> ) }Copy the code

14. Close the single label

In React, if there are no child nodes, there are two ways to close labels. But there is no ambiguity: does this component accept children? If not, try to close the label with a single label.

// 👎 does not close the tag: does this component support children? Function Component() {return <Card text="hello"></Card>} // 👍 Single tag close function Component() {return <Card text="hello"/> }Copy the code

conclusion

This article mainly from the most commonly used variables, functions, components of the three dimensions, layer by layer in-depth, belongs to the first article in this series. If you have any questions or objections, please feel free to leave comments.

Reference: github.com/jackiewille…