Advanced Guidelines for Reaction

Keywords: React TypeScript Attribute Javascript

Reference website

https://react.docschina.org/docs/jsx-in-depth.html

Deep into JSX

Essentially, JSX is just a grammatical sugar for React. createElement (component, props,... Children) methods.

<MyButton color="blue" shadowSize={2}>
  Click Me
</MyButton>

Compile to:

React.createElement(
  MyButton, // Component name
  {color: 'blue', shadowSize: 2}, // props
  'Click Me'  //children
)

Specify React element type (validate component name)

React must be in scope

Because JSX is compiled into calls to React.createElement methods, the React library must always be in scope in your JSX code.

// Although neither React nor CustomButton are invoked directly in the code, the React library must always be in scope.
import React from 'react';
import CustomButton from './CustomButton';

function WarningButton() {
  // return React.createElement(CustomButton, {color: 'red'}, null);
  return <CustomButton color="red" />;
}

If you load React with the < script > tag, it is already in scope, in the form of React global variables.

Point representation for JSX types (component namespaces)

You can easily export many React components from a module.

import React from 'react';

const MyComponents = {
  DatePicker: function DatePicker(props) {
    return <div>Imagine a {props.color} datepicker here.</div>;
  },
  DatePicker2: function DatePicker(props) {
    return <div>Imagine a {props.color} datepicker here.</div>;
  }
  DatePicker3: function DatePicker(props) {
    return <div>Imagine a {props.color} datepicker here.</div>;
  }
}

function BlueDatePicker() {
  return <MyComponents.DatePicker color="blue" />;
}

User-defined components must be capitalized

When the element type begins with a lowercase letter, it represents a built-in component, such as <div> or <span>, which causes the string'div'or'span' to be passed to React.createElement. Types that begin with capital letters, such as <Foo/> compiled to React.createElement(Foo), and correspond to components that you define or import in a JavaScript file.

Select types at runtime

You can't use a general expression as a label for a React element. If you really want to use a general expression to determine the type of a React element, assign it to a variable at the beginning of the capitals. This usually happens when you want to render different components based on attributes:

import React from 'react';
import { PhotoStory, VideoStory } from './stories';

const components = {
  photo: PhotoStory,
  video: VideoStory
};

function Story(props) {
  // Wrong! The JSX tag name cannot be an expression.
  return <components[props.storyType] story={props.story} />;
}

// modify
function Story(props) {
  // Correct! The JSX tag name can be a variable that begins with a capitalization.
  const SpecificStory = components[props.storyType];
  return <SpecificStory story={props.story} />;
}

JSX Properties (Props)

Use JavaScript expressions as attributes

<MyComponent foo={1 + 2 + 3 + 4} />

if statements and for loops are not expressions in JavaScript, so they cannot be used directly in JSX, but you can put them in the surrounding code. For example:

function NumberDescriber(props) {
  let description;
  if (props.number % 2 == 0) {
    description = <strong>even</strong>;
  } else {
    description = <i>odd</i>;
  }
  return <div>{props.number} is an {description} number</div>;
}

string constant

You can pass string constants as attribute values. The following two JSX expressions are equivalent:

<MyComponent message="hello world" />

<MyComponent message={'hello world'} />

When passing a string constant, the value is HTML non-escaped, so the following two JSX expressions are the same:

<MyComponent message="&lt;3" />

<MyComponent message={'<3'} />

Property defaults to "True"

If you do not pass a value to an attribute, it defaults to true. So the following two JSX are equivalent:

<MyTextBox autocomplete />

<MyTextBox autocomplete={true} />

Normally, we don't recommend this, because it will work with ES6 Object Concise Representation Confusion. For example, {foo} is the abbreviation of {foo: foo} rather than {foo: true}. This works because it fits HTML.

Expand properties

If you already have a props object and want to pass it in JSX, you can use... as the "spread" operator to pass the entire property object. The following two components are equivalent:

function App1() {
  return <Greeting firstName="Ben" lastName="Hector" />;
}

function App2() {
  const props = {firstName: 'Ben', lastName: 'Hector'};
  return <Greeting {...props} />;
}

Generation in JSX

In a JSX expression that contains both the start tag and the end tag, the content between the two tags is passed as a special property: props.children.

string literal

<MyComponent>Hello world!</MyComponent>
// props.children is that string

JSX removes empty lines and spaces at the beginning and end. New lines adjacent to the label will also be removed, and newlines within the string constant will be compressed into a space, so the following are equivalent: (to wrap the newlines with the label)

<div>Hello World</div>

<div>
  Hello World
</div>

<div>
  Hello
  World
</div>

<div>

  Hello World
</div>

JSX progeny

You can provide more JSX elements as descendants, which is very useful for nested display components:

<MyContainer>
  <MyFirstComponent />
  <MySecondComponent />
</MyContainer>

React components can also return an array containing multiple elements:

render() {
  // There is no need to wrap elements in an array with additional elements!
  return [
    // Don't forget key:)
    <li key="A">First item</li>,
    <li key="B">Second item</li>,
    <li key="C">Third item</li>,
  ];
}

JavaScript expressions as descendants

This is useful for rendering lists of JSX expressions of any length. For example, the following will render an HTML list:

function Item(props) {
  return <li>{props.message}</li>;
}

function TodoList() {
  const todos = ['finish doc', 'submit pr', 'nag dan to review'];
  return (
    <ul>
      {todos.map((message) => <Item key={message} message={message} />)}
    </ul>
  );
}

(callback) function as offspring

Normally, JavaScript expressions inserted into JSX will be recognized as strings, React elements, or a list of these. However, props.children can pass any kind of data like other attributes, not just the kind of data React knows how to render. For example, if you have a custom component, you can make it take a callback as props.children:

// Calls the children callback numTimes to produce a repeated component
function Repeat(props) {
  let items = [];
  for (let i = 0; i < props.numTimes; i++) {
    // Take a callback as props.children
    items.push(props.children(i));
  }
  return <div>{items}</div>;
}

function ListOfTenThings() {
  return (
    <Repeat numTimes={10}>
      {(index) => <div key={index}>This is item {index} in the list</div>}
    </Repeat>
  );
}

Boolean values, Null and Undefined are ignored

false, null, undefined and true are all valid offspring, but they are not rendered. The following JSX expression renders the same thing:

<div />

<div></div>

<div>{false}</div>

<div>{null}</div>

<div>{undefined}</div>

<div>{true}</div>

This is very useful in determining whether to render React elements based on conditions. The following JSX renders the < Header /> component only when showHeader is true.

<div>
  {showHeader && <Header />}
  <Content />
</div>

Make sure that & & the previous expression is always Boolean, otherwise it will be printed

<div>
   // Because when props.message is an empty array, it prints 0
  {props.messages.length &&
    <MessageList messages={props.messages} />
  }
</div>

// Correct writing
<div>
  {props.messages.length > 0 &&
    <MessageList messages={props.messages} />
  }
</div>

Instead, if you want something like false, true, null, or undefined to appear in the output, you have to first put it in Convert to a string :

<div>
  My JavaScript variable is {String(myVariable)}.
</div>

Type checking using PropTypes

Note: React.PropTypes have been discarded since React v15.5. Please use prop-types  Library instead.

For some applications, you can also use the ____________ Flow Or TypeScript Such JavsScript extensions allow for type checking of the entire application. But even if you don't use them, React has some built-in type checking capabilities. To check the properties of components, you need to configure special propTypes properties:

import PropTypes from 'prop-types';

class Greeting extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}

Greeting.propTypes = {
  name: PropTypes.string
};

PropTypes contains a set of validators that can be used to ensure that the data you receive is valid. In this example, we used PropTypes.string. When you pass invalid values to attributes, the JavsScript console prints a warning. For performance reasons, propTypes are checked only in development mode.

Various PropTypes

import PropTypes from 'prop-types';

MyComponent.propTypes = {
  // You can declare attributes as the following JS native types
  optionalArray: PropTypes.array,
  optionalBool: PropTypes.bool,
  optionalFunc: PropTypes.func,
  optionalNumber: PropTypes.number,
  optionalObject: PropTypes.object,
  optionalString: PropTypes.string,
  optionalSymbol: PropTypes.symbol,

  // Any renderable element (including numbers, strings, subelements or arrays).
  optionalNode: PropTypes.node,

  // A React element
  optionalElement: PropTypes.element,

  // You can also declare attributes as instances of a class, using JS's
  // instanceof operator implementation.
  optionalMessage: PropTypes.instanceOf(Message),

  // You can also limit the value of your attribute to one of the specific values.
  optionalEnum: PropTypes.oneOf(['News', 'Photos']),

  // Limit it to be an object of one of the enumeration types
  optionalUnion: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.instanceOf(Message)
  ]),

  // An array of specified element types
  optionalArrayOf: PropTypes.arrayOf(PropTypes.number),

  // An object of a specified type
  optionalObjectOf: PropTypes.objectOf(PropTypes.number),

  // An object that specifies an attribute and its type
  optionalObjectWithShape: PropTypes.shape({
    color: PropTypes.string,
    fontSize: PropTypes.number
  }),

  // You can also add `isRequired'after any PropTypes attribute` 
  // Suffix, so that if the parent component of this property is not provided, warning information will be printed
  requiredFunc: PropTypes.func.isRequired,

  // Any type of data
  requiredAny: PropTypes.any.isRequired,

  // You can also specify a custom validator. It should return when validation fails
  // An Error object instead of `console.warn'or throwing an exception.
  // But it doesn't work in `oneOfType'.
  customProp: function(props, propName, componentName) {
    if (!/matchme/.test(props[propName])) {
      return new Error(
        'Invalid prop `' + propName + '` supplied to' +
        ' `' + componentName + '`. Validation failed.'
      );
    }
  },

  // But you can provide a custom `arrayOf'or `objectOf'.` 
  // Verifier, which should return an Error object when validation fails. It is used.
  // For each value of the validation array or object. The first of the first two parameters of the validator is an array
  // Or objects themselves, the second is their corresponding keys.
  customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
    if (!/matchme/.test(propValue[key])) {
      return new Error(
        'Invalid prop `' + propFullName + '` supplied to' +
        ' `' + componentName + '`. Validation failed.'
      );
    }
  })
};

Limit single offspring

Using PropTypes. elements, you can specify that only one descendant is passed

import PropTypes from 'prop-types';

class MyComponent extends React.Component {
  render() {
    // This must be exactly one element or it will warn.
    const children = this.props.children;
    return (
      <div>
        {children}
      </div>
    );
  }
}

MyComponent.propTypes = {
  // Must fill
  children: PropTypes.element.isRequired
};

Property default value

You can define default values for props by configuring defaultProps:

class Greeting extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}

// Specify default values for attributes:
Greeting.defaultProps = {
  name: 'Stranger'
};

// Render "Hello, Stranger":
ReactDOM.render(
  <Greeting />,
  document.getElementById('example')
);

If you use something like ____________ transform-class-properties For Babel converters, you can also declare defaultProps as static properties in React component classes. This grammar hasn't been passed yet. It needs to be compiled step by step in the browser. For more information, see Class field proposal.

class Greeting extends React.Component {
  static defaultProps = {
    name: 'stranger'
  }

  render() {
    return (
      <div>Hello, {this.props.name}</div>
    )
  }
}

Static type checking

Image Flow Sum TypeScript Such a static type checker can identify certain types of problems before running the code. They can also improve the workflow of developers by adding automated completion functions.

 

Flow

Flow A static type checker for JavaScript code. It was developed on Facebook and is often used with React. It lets you annotate variables, functions, and React components with special type syntax, and detect errors as early as possible. You can read Flow introduction To understand the basic knowledge.

Add Flow to a project

If you use npm Operation:

npm install --save-dev flow-bin
// The second command creates a Flow configuration file that you need to submit.
npm run flow init

Finally, add flow to the "scripts" section of your package.json:

{
  // ...
  "scripts": {
    "flow": "flow",
    // ...
  },
  // ...
}

Stripping Flow syntax from compiled code

Flow extends the JavaScript language by using special syntax for type annotations. However, the browser does not know this syntax, so we need to make sure that it does not end in the compiled JavaScript package sent to the browser.

The exact approach depends on the tools you use to compile JavaScript.

Create React App

If your project is used. Create React App Established, congratulations! Flow has been stripped by default, so you don't need to do anything at this stage.

Other tools

Run Flow

If you follow the instructions above, you should be able to run Flow the first time.

npm run flow

You should see a message like this:

No errors!
✨  Done in 0.17s.

Add Flow type annotations

By default, Flow only checks the files containing this annotation:

Usually it is placed at the top of the file.

// @flow

Also have One choice Flow can be forced to check all files without considering comments. It may be too cumbersome for an existing project, but it would be reasonable for a new project if you wanted to organize it entirely with Flow.

Now you are all ready! We recommend looking at the following resources for more information about Flow:

TypeScript

TypeScript It is a programming language developed by Microsoft. It is a type superset of JavaScript that contains its own compiler. As a typed language, Typescript can detect errors at build time long before your application comes online. You can be there. Here Learn more about using TypeScript in React.

Add TypeScript to a project

npm install --save-dev typescript

Installing TypeScript allows us to access the tsc command. Before configuring, let's add tsc to the "scripts" section of package. json:

{
  // ...
  "scripts": {
    "build": "tsc",
    // ...
  },
  // ...
}

Configure the TypeScript compiler

Unless we tell the compiler what to do, it will be of no use to us. In TypeScript, these rules are defined in a special file called tsconfig.json. Run the following command to generate the file:

tsc --init

Looking at the tsconfig.json generated now, you can see that there are many options to configure the compiler. For a detailed description of all options, Click Here.

Among many options, we'll see rootDir and outDir. The compiler will receive the typescript file as it is and generate the javascript file. However, we do not want to confuse source files with compiled output.

We will solve this problem in two steps:

  • First, let's arrange our project structure like this. We put all the source code in the src directory.
├── package.json
├── src
│   └── index.ts
└── tsconfig.json
  • Next, we will tell the compiler where the source code is and where to put the output after compilation.
// tsconfig.json

{
  "compilerOptions": {
    // ...
    "rootDir": "src",
    "outDir": "build"
    // ...
  },
}

Excellent! Now when we run the build script, the compiler will output the generated javascript code to the build folder. TypeScript React Starter Provides a tsconfig.json file with a set of configurations for you to start with.

Normally, you don't want to keep the generated JavaScript in source code management, so make sure that the generated folder is added to.gitignore.

File extension

In React, you are most likely to write your components in.js files. In TypeScript, we have two file extensions:

The.ts is the default file extension, and.tsx is a special extension used to include JSX code.

Run TypeScript

npm run build

If you don't see the output, it means that it's compiled completely.

type definition

todo...

Use TypeScript with Create React App

react-scripts-ts A create-react-app project is automatically configured to support TypeScript. You can use it like this:

create-react-app my-app --scripts-version=react-scripts-ts

Note that it is a third-party project and not part of Create React App.

You can also try. typescript-react-starter.

You're ready to write code! We recommend looking at the following resources to learn more about TypeScript:

Reason

todo...

Kotlin

todo...

Refs & DOM

Refs provides a way to access DOM nodes or React elements created in render methods. (ref attribute of vue dom)

In a typical React data stream, Property (props) It is the only way for parent components to interact with child components. To modify the subcomponent, you need to re-render it with the new props. However, in some cases you need to force modification of subcomponents out of typical data streams. The subcomponent to be modified can be either an instance of a React component or a DOM element. In both cases, React provides a solution.

When to use Refs

Here are a few examples of refs that are suitable for use: refs, refs, refs, refs, refs, refs, refs, refs, refs, refs, refs, refs, refs, refs, refs, ref

  • Processing focus, text selection or media control.
  • Trigger mandatory animation.
  • Integrating third-party DOM Libraries

Personally, I think it is to directly obtain the dom node information (including attributes, methods) of a subcomponent or element within a single component.

If it can be implemented declaratively, try to avoid refs.

For example, instead of exposing the open() and close() methods directly on the Dialog component, it is better to pass the isOpen attribute.

Don't overuse Refs

You may first think of using refs to update components in your application. If this is the case, take a moment to rethink the position of the state attribute in the component layer. Usually you want to understand that it would be more appropriate to upgrade the component level where state is located.

 

The following example has been updated with the React.createRef() API introduced in React v16.3. If you are using an earlier release of React, we recommend it Callback refs.

Create Refs

Use React.createRef() to create refs and get the React element through the ref attribute. When building components, refs are usually assigned to an attribute of the instance so that you can use them anywhere in the component.

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    // React.createRef creates ref
    this.myRef = React.createRef();
  }
  render() {
    // refs are usually assigned to an attribute of an instance
    return <div ref={this.myRef} />;
  }
}

Visit Refs

When a ref attribute is passed to an element in a render function, a reference to a node can be accessed using the current attribute in Ref.

// Accessing references to nodes
const node = this.myRef.current;

The value of ref depends on the type of node:

  • When the ref attribute is used for a common HTML element, React.createRef() creates ref by receiving the underlying DOM element as its current attribute.
  • When the ref attribute is used for a custom class component, the ref object receives the mounted instance of the component as its current.
  • You can't use ref attributes on functional components because they don't have instances.

The following code uses ref to store references to DOM nodes:

class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
    // Create ref to store textInput DOM elements
    this.textInput = React.createRef();
    this.focusTextInput = this.focusTextInput.bind(this);
  }

  focusTextInput() {
    // Direct use of native API s to focus text input boxes
    // Note: Get DOM nodes by "current"
    this.textInput.current.focus();
  }

  render() {
    // Tell React that we want to associate <input> ref with the `textInput'created in the constructor
    return (
      <div>
        <input
          type="text"
          ref={this.textInput} />
          
        <input
          type="button"
          value="Focus the text input"
          onClick={this.focusTextInput}
        />
      </div>
    );
  }
}

React passes DOM elements into the current attribute when the component is loaded, and returns null when it is unloaded. ref updates occur before componentDidMount or componentDidUpdate lifecycle hooks.

If we want to wrap the CustomTextInput above to simulate being clicked immediately after mounting, we can use ref to access the custom input and manually call its focusTextInput method:

class AutoFocusTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }

  componentDidMount() {
    this.textInput.current.focusTextInput();
  }

  render() {
    return (
      <CustomTextInput ref={this.textInput} />
    );
  }
}

You cannot use ref attributes on functional components because they have no instances: (ref cannot be bound on functional elements)

function MyFunctionalComponent() {
  return <input />;
}

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }
  render() {
    // This will * not * work!
    return (
      <MyFunctionalComponent ref={this.textInput} />
    );
  }
}

However, you can use ref inside a functional component as long as it points to a DOM element or class component: (ref can be bound inside a functional component)

function CustomTextInput(props) {
  // textInput must be declared here so that the ref callback can refer to it
  let textInput = null;

  function handleClick() {
    textInput.focus();
  }

  return (
    <div>
      <input
        type="text"
        ref={(input) => { textInput = input; }} />
      <input
        type="button"
        value="Focus the text input"
        onClick={handleClick}
      />
    </div>
  );  
}

Exposing DOM nodes to parent components

Although you can Adding ref to subcomponents But this is not an ideal solution, because you can only get component instances instead of DOM nodes. Moreover, it is not valid on functional components.

If you use React 16.3 or higher, we recommend using React 16.3 in this case. ref forwarding . ref forwarding enables components to expose refs of subcomponents as they expose their refs. About how to expose DOM nodes of child components to parent components, Forwarding documents in ref There is a detailed example.

If you use React 16.2 or less, or you need more flexibility than ref forwarding, you can use it. This alternative Transfer ref directly as prop with a special name.

Callback Refs

React also supports another way of setting ref, called callback ref, to more carefully control when ref is set and removed.

You pass a function. This function accepts instances of React components or HTML DOM elements as parameters to store them and make them accessible elsewhere.

class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);

    this.textInput = null;
    
    // The ref callback function is used to store references to DOM nodes in the attributes of the instance.
    // Accept instances of React components or HTML DOM elements as parameters to store them and make them accessible elsewhere
    this.setTextInputRef = element => {
      this.textInput = element;
    };

    this.focusTextInput = () => {
      // Direct use of native API s to focus text input boxes
      if (this.textInput) this.textInput.focus();
    };
  }

  componentDidMount() {
    // Text box automatically gets focus after rendering
    this.focusTextInput();
  }

  render() {
    // Store DOM nodes of text input boxes into React using `ref'callbacks
    // Instances (such as this.textInput)
    return (
      <div>
        <input
          type="text"
          ref={this.setTextInputRef}
        />
        <input
          type="button"
          value="Focus the text input"
          onClick={this.focusTextInput}
        />
      </div>
    );
  }
}

React passes the DOM element into the ref callback function when the component is mounted and calls it, and null when it is unloaded and calls it. The ref callback function is called before the componentDidMount and componentDidUpdate life cycle functions (consistent with accessing ref)

 

You can pass callback refs between components, just as you can pass object refs created through React.createRef().

function CustomTextInput(props) {
  return (
    <div>
      <input ref={props.inputRef} />
    </div>
  );
}

class Parent extends React.Component {
  render() {
    return (
      <CustomTextInput
        inputRef={el => this.inputElement = el}
      />
    );
  }
}

In the example above, the ref callback function passed to Parent is passed to CustomTextInput as inputRef, and then CustomTextInput is passed to <input> through the ref attribute. Finally, this.inputElement in Parent will be set to the DOM node corresponding to the < input > element in CustomTextIput (that is, this.inputElement of parent equals the input DOM node of CustomTextInput)

Uncontrolled components

In most cases, we recommend the use of ____________ Controlled component Implement forms. In controlled components, form data is processed by React components. If form data is processed by DOM, the alternative is to use uncontrolled components.

 

To write a non-controlled component instead of an event handler for each state update, you can Using ref  Get form values from DOM.

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.input.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
           {/* Complete a non-controlled component through ref */}
          <input type="text" ref={(input) => this.input = input} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

Because non-controlled components store real data in DOM, it is easier to integrate both React and non-React code when using non-controlled components. If you want to be quick and easy, you can reduce the amount of code. Otherwise, you should use controlled components.

If it's still unclear what type of component to choose in a particular situation, you should read This is about controlled and uncontrolled form input Learn more.

Default value

During the lifetime of React, the value attribute on the form element will override the value in the DOM. When using uncontrolled components, you usually want React to specify an initial value for them, but you no longer control subsequent updates. You can specify a defaultValue attribute instead of a value.

render() {
  return (
    <form onSubmit={this.handleSubmit}>
      <label>
        Name:
        {/* Use defaultValue to set default values */}
        <input
          defaultValue="Bob"
          type="text"
          ref={(input) => this.input = input} />
      </label>
      <input type="submit" value="Submit" />
    </form>
  );
}

Similarly, <input type="checkbox"> and <input type="radio"> support defaultChecked, <select> and <textarea> support defaultValue.

File input label

In HTML, <input type="file"> allows users to select one or more files from their device storage to upload to the server, or through File API Operate.

<input type="file" />

In React, <input type="file"/> is always an uncontrolled component because its value can only be set by the user, not programmatically.

The following example shows how to create ref nodes to access files in the submission handler:

class FileInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  handleSubmit(event) {
    event.preventDefault();
    alert(
      /* Obtain the corresponding value from the object obtained by ref */ 
      `Selected file - ${this.fileInput.files[0].name}`
    );
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Upload file:
          {/* Get the input value through a ref callback function */}
          <input
            type="file"
            ref={input => {
              this.fileInput = input;
            }}
          />
        </label>
        <br />
        <button type="submit">Submit</button>
      </form>
    );
  }
}

ReactDOM.render(
  <FileInput />,
  document.getElementById('root')
);

performance optimization

When updating the UI, React uses several ingenious techniques internally to minimize the number of DOM operations.

Use production version

When detecting performance problems in React applications, be sure to use a compressed production version.

By default, React contains many warnings that are helpful in the development process. However, this can lead to larger and slower React. Therefore, when deploying an application, make sure that the production version is used.

If you are not sure whether the build process is correct, you can install it React Developer Tool (chrome) . When you visit the React page of a production model, the icon of the tool has a black background:

When you visit the React page of a development model, the icon of the tool has a red background:

It's better to use development mode when developing applications and change production mode when deploying applications.

The following is the process of building production applications.

Create React App

If your project is based on Create React App Created, run the following code:

npm run build

This will create a production version of the application in the project's build / folder.

Note that this is necessary only when a project is released and npm start is used for normal development.

Other creation methods use the production version method

Using Chrome Performance Archive Components

In development mode, using performance tools in supported browsers can intuitively understand when components are mounted, updated and uninstalled. For example:

In Chrome browser:

  1. Add the query string? react_perf to the project address bar (for example, http://localhost:3000/?react_perf).

  2. Open Chrome Development Tools Performance Click Record on the tab.

  3. Perform the actions you want to analyze. Don't record more than 20 seconds, or Chrome may hang up.

  4. Stop recording.

  5. React events will be categorized under the User Time tag.

For more details, please refer to Ben Schwarz's article.

Note that because these numbers are relative, components run faster in production versions. However, it can also help you understand when unrelated components will be updated incorrectly, and the depth and frequency of your component updates.

Currently only Chrome, Edge and IE support this feature in browsers, but we use this standard User Timing API So we expect more browsers to add support for it.

Virtualized Long List

todo...

Avoid coordination

todo...

shouldComponentUpdate(nextProps, nextState) {
  return true;
}

If you know that in some cases your component does not need to be updated, you can return false within shouldComponentUpdate to skip the entire rendering process, which includes calling render() instructions on the component and subsequent content.

Should Component Update

This is a subtree of a component. For each of these components, SCU indicates the return content of shouldComponentUpdate, vDOMEq indicates whether the rendered React element is equal to the original element, and finally, the color of the circle indicates whether the component needs to be re-rendered.

Because shouldComponentUpdate of the subtree rooted in C2 returns false, React will not attempt to render C2, or even call shouldComponentUpdate on C4 and C5.

For C1 and C3, shouldComponentUpdate returns true, so React goes deep into the branches and checks them. The shouldComponentUpdate of C6 returns true, because the elements to be rendered are not equal to the original elements, React updates the DOM node.

The last interesting case is C8. React needs to render the component, but because the component element returns the same value as the original element, it does not update the DOM node.

Note that React only needs to update C6, because it is inevitable. For C8, it avoids rendering by comparing the elements to be rendered with the original elements. For subtrees of C2 and C7, they do not even perform a comparison because we set shouldComponentUpdate to false and render is not invoked.

class CounterButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = {count: 1};
  }

  shouldComponentUpdate(nextProps, nextState) {
    if (this.props.color !== nextProps.color) {
      return true;
    }
    if (this.state.count !== nextState.count) {
      return true;
    }
    return false;
  }

  render() {
    return (
      <button
        color={this.props.color}
        onClick={() => this.setState(state => ({count: state.count + 1}))}>
        Count: {this.state.count}
      </button>
    );
  }
}

The power of data that does not mutate

The simplest way to avoid such problems is to avoid using attributes or states whose values may mutate. For example, the handleClick in the example above should be rewritten with concat (array splicing):

handleClick() {
  this.setState(prevState => ({
    words: prevState.words.concat(['marklar'])
  }));
}

ES6 supports array Expand grammar It can be made easier. If you use Create React App, this grammar is available by default.

handleClick() {
  this.setState(prevState => ({
    words: [...prevState.words, 'marklar'],
  }));
};

To implement code without mutating the original object, we can use Object.assign Method:

function updateColorMap(colormap) {
  return Object.assign({}, colormap, {right: 'blue'});
}

There is a JavaScript proposal to add Object expansion properties To make it easier to update objects without mutating them:

function updateColorMap(colormap) {
  return {...colormap, right: 'blue'};
}

Use non-mutable data structures

todo...

Using ES6

todo...

Declare default properties

If you create a component using the class keyword, you can write the custom property object directly into the defaultProps property of the class:

class Greeting extends React.Component {
  // ...
}

Greeting.defaultProps = {
  name: 'Mary'
};

Automatic binding

For React components created with class keywords, the method in the component is not automatically bound to this. Similarly, the method on the instance will not bind this through the instance generated by ES6 class. Therefore, you need to manually add.bind(this) to the method in the constructor:

class SayHello extends React.Component {
  constructor(props) {
    super(props);
    this.state = {message: 'Hello!'};
    // This is a key business.
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    alert(this.state.message);
  }

  render() {
    // Because `this.handleClick'has been bound to an instance, we can use it to handle click events.
    return (
      <button onClick={this.handleClick}>
        Say hello
      </button>
    );
  }
}

Mixin

ES6 itself does not include mixed support. Therefore, if you use the class keyword to create components, you can't use the blending function.

We've also found a lot of code libraries that use mix-ins and then have problems. Therefore, we do not recommend mixing in ES6.

The following is for reference only

If completely different components have similar functions, this will result. Cross-cutting concerns . In order to solve this problem, it is necessary to use ___________ createReactClass When creating React components, introducing mix-in functionality is a good solution.

A common usage scenario is that when a component wants to update every other time, the simplest way is to use setInterval(). But more importantly, if this feature is not needed in subsequent code, you should delete it in order to save memory. React provides Life cycle approach So you can know when a component will be created or destroyed. Let's first create a mix-in using setInterval(), which will also be destroyed when the component is destroyed.

var SetIntervalMixin = {
  componentWillMount: function() {
    this.intervals = [];
  },
  setInterval: function() {
    this.intervals.push(setInterval.apply(null, arguments));
  },
  componentWillUnmount: function() {
    this.intervals.forEach(clearInterval);
  }
};

var createReactClass = require('create-react-class');

var TickTock = createReactClass({
  mixins: [SetIntervalMixin], // Use mixing
  getInitialState: function() {
    return {seconds: 0};
  },
  componentDidMount: function() {
    this.setInterval(this.tick, 1000); // Call the method of mix-in
  },
  tick: function() {
    this.setState({seconds: this.state.seconds + 1});
  },
  render: function() {
    return (
      <p>
        React has been running for {this.state.seconds} seconds.
      </p>
    );
  }
});

ReactDOM.render(
  <TickTock />,
  document.getElementById('example')
);

If a component has multiple mixtures, and several of them define the same lifecycle methods (for example, they will be executed when the component is destroyed), then these lifecycle methods will be invoked. By incorporating defined methods, the order of execution is the same as that of definition, and will be executed after the method on the component is executed.

Not using JSX

JSX is not required when writing React. When you don't want to install compiler tools in your build environment, it's convenient to write React without JSX.

Each JSX element is just a grammatical sugar of React. createElement (component, props,... Children).

class Hello extends React.Component {
  render() {
    return <div>Hello {this.props.toWhat}</div>;
  }
}

ReactDOM.render(
  <Hello toWhat="World" />,
  document.getElementById('root')
);

It can be compiled into the following code that does not use JSX:

class Hello extends React.Component {
  render() {
    return React.createElement('div', null, `Hello ${this.props.toWhat}`);
  }
}

ReactDOM.render(
  React.createElement(Hello, {toWhat: 'World'}, null),
  document.getElementById('root')
);

 

 

Posted by jp2php on Tue, 30 Apr 2019 09:50:38 -0700