1 the React based

1.1 JSX base

JSX is react. createElement(Component, props,… The syntactic sugar of the children function.

JSX code:

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

Will compile to:

React.createElement(
  MyButton,
  {color: 'blue'.shadowSize: 2},
  'Click Me'
)
Copy the code

1.1.1 Expressions can be embedded in JSX

const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;

ReactDOM.render(
  element,
  document.getElementById('root'));Copy the code

1.1.2 JSX properties

Attribute values can be specified as string literals by using quotes:

<MyComponent message={'hello world'} / >Copy the code

We can use curly braces {} to insert a JavaScript expression in the attribute value:

const element = <img src={user.avatarUrl}></img>;
Copy the code

The default value for Props is true:

<MyTextBox autocomplete />

/ / equivalent to

<MyTextBox autocomplete={true} />
Copy the code

Properties on

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

/ / equivalent to

function App2() {
  return <Greeting firstName="Ben" lastName="Hector" />;
}
Copy the code

Props is read-only. They should not be modified in any way. If you want to modify some values in response to user input or network response, use state instead.

// Error!
props.number = 42;
Copy the code

1.1.3 Child elements in JSX

The JSX expression content contained between the start and end tags is passed to the outer component as a specific property props. Children. There are several different ways to pass child elements:

String literals

You can place the string between the start and end tags, and at this point props. Children is just that string. This is useful for many built-in HTML elements. Such as:

<MyComponent>Hello world! </MyComponent>Copy the code

JSX

Child elements are allowed to be composed of multiple JSX elements. This is useful for nested components:

<MyContainer>
  <MyFirstComponent />
  <MySecondComponent />
</MyContainer>
Copy the code

JavaScript expression

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>
  );
}
Copy the code

Boolean types, Null, and Undefined

False, null, undefined, and true are legal child elements, but they are not rendered.

1.1.4 JSX prevents injection attacks

The React DOM escapes by default before rendering all input.

1.1.5 React must be in scope

Because JSX compiles to the react. createElement call form, the React library must be included in the JSX code scope.

1.1.6 named

The property prop must be named after the hump

Because JSX is syntactically closer to JavaScript than HTML, React DOM uses camel name to define attribute names, rather than the naming convention for HTML attribute names.

Custom components must begin with a capital letter

An element starting with a lowercase letter represents an HTML built-in component, such as

or
, which generates the corresponding string ‘div’ or ‘span’ to be passed to React. CreateElement.

Uppercase elements correspond to components introduced in JavaScript or custom, such as
which are compiled to react.createElement (Foo).

1.2 Conditional Rendering

1.2.1 If operator

function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {
    return <UserGreeting />;
  }
  return <GuestGreeting />;
}
Copy the code

1.2.2 Render with the && operator

function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  return (
    isLoggedIn && <Greeting/>)}Copy the code

1.2.3 Rendering with ternary operators

function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  return (
    isLoggedIn ? <UserGreeting> :<GuestGreeting />)}Copy the code

1.2.4 Block component rendering

In rare cases, you may want to hide components. To do this, you can have the Render method return NULL directly without doing any rendering.

1.3 List & Key

1.3.1 Basic list components

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) = >
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}
Copy the code

1.3.2 key

Key helps React identify which elements have changed, such as being added or removed. So you should give each element in the array a definite identity.

An element’s key should ideally be a unique string that the element has in the list. Typically, we use the ID in the data as the element’s key.

If the order of list items may change, we do not recommend using an index as a key value, as this can lead to poor performance and possibly component state issues. If you choose not to specify an explicit key, React will default to using the index as the key for list items.

2. Element rendering

2.1 Render elements as DOM

Suppose your HTML file has a root node somewhere

<div id="root"></div>
Copy the code

To render a React element into the root DOM node, simply pass them together to reactdom.render ().

const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));
Copy the code

The page displays “Hello, world”.

2.2 Update rendered elements

React elements are immutable objects. Once created, you can’t change its child elements or attributes.

2.2.1 ReactDOM. Render ()

One way to update the UI is to create a brand new element and pass it to reactdom.render ().

Although every second we create a new element that describes the entire UI tree, the React DOM only updates what actually changes, which is the text node in the example.

function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  ReactDOM.render(element, document.getElementById('root'));
}

setInterval(tick, 1000);
Copy the code

2.2.2 setState ()

React will know that the state has changed and will recall the Render () method to determine what to display on the page. This time, the this.state.date in the render() method is different, which renders the updated time, and React updates the DOM accordingly.

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date(a)}; }componentDidMount() {
    this.timerID = setInterval(
      () = > this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()}); }render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock />.document.getElementById('root'));Copy the code

2.3 setState ()

Updates to State can be asynchronous. React may combine multiple setState() calls into one call for performance reasons, because this.props and this.state may update asynchronously, so you should not rely on their values to update the next state. To solve this problem, make setState() accept a function instead of an object. This function uses a state as the first parameter and props as the second parameter when the update was applied:

// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

// Correct
this.setState((state, props) = > ({
  counter: state.counter + props.increment
}));
Copy the code

State updates are merged

When you call setState(), React merges the objects you provide into the current state.

3. Composite events

3.1 Event Handling

3.1.1 binding this

Bind in the constructor

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

  handleClick() {
    console.log('this is:'.this);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>); }}Copy the code

The correct binding callback using class Fields:

class LoggingButton extends React.Component {
  handleClick = () = > {
    console.log('this is:'.this);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>); }}Copy the code

Binding in Render

class Foo extends Component {
  handleClick() {
    console.log('Click happened');
  }
  
  render() {
    return (
      <button onClick={this.handleClick.bind(this)}>
        Click me
      </button>); }}Copy the code

3.1.2 the preventDefault

You cannot prevent the default behavior by returning false. PreventDefault must be explicitly used.

// HTML
<a href="#" onclick="console.log('The link was clicked.'); return false">
  Click me
</a>

// React
function ActionLink() {
  function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
  }

  return (
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}
Copy the code

3.1.3 Passing Parameters

<button onClick={(e) = > this.deleteRow(id, e)}>Delete Row</button>
Copy the code

8 the form

8.1 Controlled Components

If the value of an input form element is controlled by React, it is called a controlled component. When a user enters data into a controlled component, it triggers an event handler that changes the state, and it is up to your code to determine whether the input is valid or not (if so, it is rerendered with the updated value). If you do not rerender, the form elements remain the same.

In HTML, form elements such as ,

(1) input

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ' '};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('Submitted by name:' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>Name:<input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>); }}Copy the code

(2) the textarea label

In HTML, the

</textarea> </textarea>Copy the code

In React,

<textarea value={this.state.value} onChange={this.handleChange} />
Copy the code

(3) the select tag

In HTML, < SELECT > creates drop-down list tags.

<select>
  <option value="grapefruit">grapefruit</option>
  <option value="lime">lime</option>
  <option selected value="coconut">coconut</option>
  <option value="mango">Mango.</option>
</select>
Copy the code

The coconut option is selected by default due to the Selected attribute. React does not use the selected attribute. Instead, it uses the value attribute on the root SELECT tag.

<select value={this.state.value} onChange={this.handleChange}>
  <option value="grapefruit">grapefruit</option>
  <option value="lime">lime</option>
  <option value="coconut">coconut</option>
  <option value="mango">Mango.</option>
</select>
Copy the code

You can pass arrays to the value property to support multiple options in the SELECT tag:

<select multiple={true} value={['B'.'C']} >Copy the code

(4) Processing multiple inputs

When we need to process multiple input elements, we can add a name attribute to each element and let the handler select the action to perform based on the value of event.target.name.

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true.numberOfGuests: 2
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.name === 'isGoing' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  render() {
    return (
      <form>
        <label>Participate in:<input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>Number of guests:<input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
        </label>
      </form>); }}Copy the code

(5) the default values

A prop specifying value on a controlled component prevents the user from changing the input. If you specify value but the input is still editable, you may have accidentally set value to undefined or null. The following code demonstrates this. (The input was initially locked, but became editable after a short delay.)

ReactDOM.render(<input value="hi" />, mountNode);

setTimeout(function() {
  ReactDOM.render(<input value={null} />, mountNode);
}, 1000);
Copy the code

During the React rendering life cycle, the value on the form element overrides the value in the DOM node. In uncontrolled components, you often want React to give the component an initial value, but not control subsequent updates. In this case, you can specify a defaultValue property instead of value.

render() {
  return (
    <form onSubmit={this.handleSubmit}>
      <label>
        Name:
        <input
          defaultValue="Bob"
          type="text"
          ref={this.input} />
      </label>
      <input type="submit" value="Submit" />
    </form>
  );
}
Copy the code

Similarly, and < Input Type =”radio”> support defaultChecked, and < SELECT > and

8.2 Uncontrolled Components

An uncontrolled component, like a form element that runs outside the React architecture. When the user enters data into form fields (such as input, dropdown, etc.) React doesn’t need to do anything to map the updated information. However, this also means that you cannot force the form field to set a specific value.

In HTML, allows the user to select one or more files to upload to the server, or to do so using the File API.

In React, is always an uncontrolled component because its value can only be set by the user, not controlled by code.

class FileInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.fileInput = React.createRef();
  }
  handleSubmit(event) {
    event.preventDefault();
    alert(
      `Selected file - The ${this.fileInput.current.files[0].name}`
    );
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Upload file:
          <input type="file" ref={this.fileInput} />
        </label>
        <br />
        <button type="submit">Submit</button>
      </form>
    );
  }
}

ReactDOM.render(
  <FileInput />.document.getElementById('root'));Copy the code

9 Refs forward

React supports a special REF property that can be attached to any component. This property can be an object created by the react.createref () function, a callback function, or a string (legacy API). When the ref attribute is a callback function, the function takes (depending on the element type) the underlying DOM element or class instance as its argument. This gives you direct access to DOM elements or component instances.

9.1 When to use Refs

Here are a few situations where refs are appropriate:

  1. Manage focus, text selection or media playback.
  2. Trigger the forced animation.
  3. Integrate third-party DOM libraries.

Don’t overuse Refs.

9.2 create Refs

Refs are created using react.createref () and attached to the React element via the ref attribute. When components are constructed, Refs are typically assigned to instance properties so that they can be referenced throughout the component.

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />; }}Copy the code

9.3 access Refs

When a ref is passed to an element in render, a reference to that node can be accessed in the ref’s current property.

const node = this.myRef.current;
Copy the code

The value of ref varies depending on the type of node:

The HTML element

When the ref attribute is used for HTML elements, the ref created with react.createref () in the constructor receives the underlying DOM element as its current attribute.

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

  focusTextInput() {
    // Use the native API directly to focus the text input box
    // Note that we access the DOM node through "current"
    this.textInput.current.focus();
  }

  render() {
    // Tell React that we want to associate  ref with
    // on '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>); }}Copy the code

The class components

When the REF attribute is used for a custom class component, the REF object receives the component’s mounted instance as its current attribute. Note that this is only valid if CustomTextInput is declared as class.

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

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

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

Function component

You cannot use ref attributes on function components because they have no instances.

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

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

If you want to use refs in function components, you can use forwardRef instead. In the following example, FancyButton uses the React. ForwardRef to get the ref passed to it and forward it to the DOM button it renders:

const FancyButton = React.forwardRef((props, ref) = > (
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
));

// You can get the DOM button ref directly:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
Copy the code
  1. We do this by callingReact.createRefA React ref is created and assigned to the ref variable.
  2. We pass ref down to the JSX attribute by specifying it as a JSX attribute<FancyButton ref={ref}>.
  3. React passes ref to the forwardRef function(props, ref) =>. , as its second parameter.
  4. We forward the ref parameter down to<button ref={ref}>, specifying it as a JSX property.
  5. When ref is mounted,ref.currentWill point to<button>The DOM node.

The second argument, ref, only exists when the react. forwardRef component is defined. Regular functions and class components do not accept ref arguments, and ref does not exist in props.

High order component

This technique is especially useful for higher-order components, also known as HOC. Let’s start with an example of HOC that outputs component props to the console:

function logProps(WrappedComponent) {
  class LogProps extends React.Component {
    componentDidUpdate(prevProps) {
      console.log('old props:', prevProps);
      console.log('new props:'.this.props);
    }

    render() {
      return <WrappedComponent {. this.props} / >; }}return LogProps;
}
Copy the code

We can use this HOC to log all props passed to the “Fancy Button” component:

class FancyButton extends React.Component {
  focus() {
    // ...
  }

  // ...
}

// We export LogProps instead of FancyButton.
// Although it also renders a FancyButton.
export default logProps(FancyButton);
Copy the code

One caveat to the above example is that refs will not pass through. This is because ref is not a prop property. Just like the key, it gets special processing by React. If you add a Ref to HOC, that ref will refer to the outermost container component, not the wrapped component.

This means that the refs for our FancyButton component will actually be mounted to the LogProps component:

import FancyButton from './FancyButton';

const ref = React.createRef();

// The FancyButton component we imported is HOC LogProps.
// Although the render result will be the same,
// But our ref will point to the LogProps instead of the internal FancyButton component!
// This means that we cannot call methods such as ref.current-focus ()
<FancyButton
  label="Click Me"
  handleClick={handleClick}
  ref={ref}
/>;
Copy the code

Fortunately, we can use the React.forwardRef API to explicitly forward refs to the internal FancyButton component. The React. ForwardRef takes a render function that accepts the props and ref arguments and returns a React node. Such as:

function logProps(Component) {
  class LogProps extends React.Component {
    componentDidUpdate(prevProps) {
      console.log('old props:', prevProps);
      console.log('new props:'.this.props);
    }

    render() {
      const{forwardedRef, ... rest} =this.props;

      // define the custom prop property "forwardedRef" as ref
      return <Component ref={forwardedRef} {. rest} / >; }}// the react. forwardRef callback has the second argument "ref".
  // We can pass this as a regular prop property to LogProps, such as "forwardedRef"
  // It can then be mounted to a child component wrapped around LogProps.
  return React.forwardRef((props, ref) = > {
    return <LogProps {. props} forwardedRef={ref} />;
  });
}
Copy the code

9.4 the callback Refs

Instead of passing the ref attribute created by createRef(), you pass a function that takes React component instances or HTML DOM elements as arguments so that they can be stored and accessed elsewhere.

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

    this.textInput = null;

    this.setTextInputRef = element= > {
      this.textInput = element;
    };

    this.focusTextInput = () = > {
      // Use the native DOM API to focus the text input box
      if (this.textInput) this.textInput.focus();
    };
  }

  componentDidMount() {
    // After the component is mounted, let the text box get focus automatically
    this.focusTextInput();
  }

  render() {
    // Use the 'ref' callback to store a reference to the DOM node of the text input box into React
    // on an instance (such as this.textinput)
    return (
      <div>
        <input
          type="text"
          ref={this.setTextInputRef}
        />
        <input
          type="button"
          value="Focus the text input"
          onClick={this.focusTextInput}
        />
      </div>); }}Copy the code

React will call the ref callback and pass in the DOM element when the component is mounted and null when it is unmounted. React ensures that the refs are up to date before componentDidMount or componentDidUpdate is triggered.

You can pass refs in the form of callbacks between components, just as you can pass refs for objects 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}
      />); }}Copy the code

In the example above, Parent passes its refs callback function to CustomTextInput as inputRef props, and CustomTextInput passes the same function to as a special ref attribute. As a result, this.inputElement in Parent is set to the DOM node corresponding to the input element in CustomTextInput.

If the ref callback is defined as an inline function, it is executed twice during the update process, passing in the argument NULL the first time, and then the argument DOM element the second time. This is because a new function instance is created each time it renders, so React clears the old ref and sets the new one. This can be avoided by defining the ref callback function as a class binding function, but in most cases it is irrelevant.

9.5 Obsolete API: Refs of String type

If you’ve used React before, you probably know the string ref property in the old API, such as “textInput”. You can access DOM nodes via this.refs.textInput. We don’t recommend using it because there are some issues with string refs. It is outdated and may be removed in a future release.

Note: If you are currently accessing refs using this.refs.textInput, we recommend using callbacks or the createRef API instead.

9.6 Displaying custom names in DevTools

React. ForwardRef accepts a render function. React DevTools uses this function to determine what to display for the REF forward component.

For example, the following components will show up as “ForwardRef” in DevTools:

const WrappedComponent = React.forwardRef((props, ref) = > {
  return <LogProps {. props} forwardedRef={ref} />;
});
Copy the code

If you name the render function, DevTools will also include its name (e.g. “ForwardRef(myFunction)”) :

const WrappedComponent = React.forwardRef(
  function myFunction(props, ref) {
    return <LogProps {. props} forwardedRef={ref} />; });Copy the code

10 Context

Context provides a way to pass data across the component tree without manually adding props for each layer of components.

10.1 When to Use Context

Context is designed to share data that is “global” to a component tree, such as the currently authenticated user, topic, or preferred language.

Before we use Context

class App extends React.Component {
  render() {
    return <Toolbar theme="dark" />; }}function Toolbar(props) {
  // The Toolbar component accepts an additional "theme" property, which is passed to the ThemedButton component.
  // If every single button in your application needs to know the theme value, this would be a hassle,
  // Because this value must be passed layer by layer to all components.
  return (
    <div>
      <ThemedButton theme={props.theme} />
    </div>
  );
}

class ThemedButton extends React.Component {
  render() {
    return <Button theme={this.props.theme} />; }}Copy the code

So after using the Context

// Context allows us to pass values deep into the component tree without explicitly traversing each component.
// Create a context for the current theme (" light "is the default).
const ThemeContext = React.createContext('light');
class App extends React.Component {
  render() {
    // Use a Provider to pass the current theme to the following component tree.
    // Any component, no matter how deep, can read this value.
    // In this case, we pass "dark" as the current value.
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>); }}// Intermediate components no longer have to specify the theme to pass down.
function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {
  // Specify contextType to read the current theme context.
  // React will find the nearest theme Provider and use its value.
  // In this case, the current theme value is "dark".
  static contextType = ThemeContext;
  render() {
    return <Button theme={this.context} />; }}Copy the code

10.2 Considerations before Using Context

Context is mainly used when many components at different levels need to access the same data. Use caution because this makes components less reusable.

Component composition is sometimes a better solution than context if you just want to avoid passing properties through layers.

For example, consider a Page component that layers down the user and avatarSize properties. If only the Avatar component actually needs user and avatarSize at the end, then it would be redundant to layer through these two props.

<Page user={user} avatarSize={avatarSize} />
/ /... Apply colours to a drawing gives...
<PageLayout user={user} avatarSize={avatarSize} />
/ /... Apply colours to a drawing gives...
<NavigationBar user={user} avatarSize={avatarSize} />
/ /... Apply colours to a drawing gives...
<Link href={user.permalink}>
  <Avatar user={user} size={avatarSize} />
</Link>
Copy the code

One context-free solution is to pass the Avatar component itself, so that the intermediate component doesn’t need to know props such as user or avatarSize:

function Page(props) {
  const user = props.user;
  const userLink = (
    <Link href={user.permalink}>
      <Avatar user={user} size={props.avatarSize} />
    </Link>
  );
  return <PageLayout userLink={userLink} />;
}

// Now we have components like this:
<Page user={user} avatarSize={avatarSize} />
/ /... Apply colours to a drawing gives...
<PageLayout userLink={... } />
/ /... Apply colours to a drawing gives...
<NavigationBar userLink={... } />
/ /... Apply colours to a drawing gives...
{props.userLink}
Copy the code

10.3 API

(1) React.createContext

Create a Context object. When React renders a component subscribed to the Context object, the component reads the current Context value from the closest matching Provider in the component tree.

The defaultValue parameter takes effect only if the component does not match the Provider in the tree.

const MyContext = React.createContext(defaultValue);
Copy the code

(2) Context.Provider

Each Context object returns a Provider React component, which allows the consuming component to subscribe to changes to the Context.

The Provider receives a value property and passes it to the consuming component. A Provider can be associated with multiple consumer components. Multiple providers can also be nested, with the inner layer overwriting the data in the outer layer.

<MyContext.Provider value={/* Some value */} >Copy the code

(3) Class.contextType

The contextType property mounted on the class is reassigned to a Context object created by react.createcontext (). This allows you to use this.context to consume the value of the most recent context. You can access it in any lifecycle, including the Render function.

(4) Context.Consumer

Here, the React component can also subscribe to context changes. This allows you to subscribe to the context in a functional component.

<MyContext.Consumer>
  {value= > /* Render based on context value */}
</MyContext.Consumer>
Copy the code

(5) Context.displayName

The context object accepts a property named displayName, of type string. React DevTools uses this string to determine what context is to display.

const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName';

<MyContext.Provider> // "myDisplayName. Provider" is in DevTools
<MyContext.Consumer> // "myDisplayName. Consumer" is in DevTools
Copy the code

(4) sample

Context

11 Advanced components

HOC is an advanced technique used in React to reuse component logic. HOC itself is not part of the React API; it is a design pattern based on the composite features of React.

Specifically, a higher-order component is a function that takes a component and returns a new component.

function logProps(WrappedComponent) {
  class LogProps extends React.Component {
    componentDidUpdate(prevProps) {
      console.log('old props:', prevProps);
      console.log('new props:'.this.props);
    }

    render() {
      return <WrappedComponent {. this.props} / >; }}return LogProps;
}
Copy the code

High order component

12 Portals

Portal provides an excellent solution for rendering child nodes to DOM nodes that exist outside the parent component.

ReactDOM.createPortal(child, container)
Copy the code

The first argument (child) is any renderable React child, such as an element, string, or fragment. The second argument (container) is a DOM element.

In general, when you return an element from the render method of a component, the element is mounted to its nearest parent in the DOM node. However, sometimes it is useful to insert child elements at different places in a DOM node:

render() {
  // React does not create a new div. It simply renders the child elements to 'domNode'.
  // 'domNode' is a valid DOM node that can be anywhere.
  return ReactDOM.createPortal(
    this.props.children,
    domNode
  );
}
Copy the code

A typical use case for a Portal is when the parent component has overflow: Hidden or Z-index style, but you need the child component to be able to visually “jump” out of its container. Examples are dialog boxes, hover cards, and prompt boxes.

13 render prop

The term “Render Prop” refers to a simple technique for sharing code between React components using a prop with a value of function

Components with Render Prop accept a function that returns a React element and calls it instead of implementing its own render logic.

<DataProvider render={data= > (
  <h1>Hello {data.target}</h1>)} / >Copy the code

13.1 Use Render Props to address crosscutting concerns

Now, we provide a Render method that allows

to dynamically determine what needs to be rendered, rather than cloning

components and hardcoding them to solve specific use cases.

More specifically, Render Prop is a function prop that tells components what to render.

This technology makes it very easy for us to share behavior. To get this behavior, simply render a

component with Render Prop that tells it what the current Mouse coordinates (x, y) are to render.


class Cat extends React.Component {
  render() {
    const mouse = this.props.mouse;
    return (
      <img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x.top: mouse.y}} / >); }}class Mouse extends React.Component {
  constructor(props) {
    super(props);
    this.handleMouseMove = this.handleMouseMove.bind(this);
    this.state = { x: 0.y: 0 };
  }

  handleMouseMove(event) {
    this.setState({
      x: event.clientX,
      y: event.clientY
    });
  }

  render() {
    return (
      <div style={{ height: '100vh'}}onMouseMove={this.handleMouseMove}>

        {/*
          Instead of providing a static representation of what <Mouse> renders,
          use the `render` prop to dynamically determine what to render.
        */}
        {this.props.render(this.state)}
      </div>
    );
  }
}

class MouseTracker extends React.Component {
  render() {
    return (
      <div>
        <h1>Move the mouse!</h1>
        <Mouse render={mouse= > (
          <Cat mouse={mouse} />)} / ></div>); }}Copy the code

One interesting thing about Render Prop is that you can implement most of the higher-order components (HOC) using regular components with Render Prop. For example, if you prefer to use withMouse HOC rather than

components, you can easily create one using regular

with Render Prop:

// If you really want HOC for some reason, you can easily do it
// Create one using a normal component with Render Prop!
function withMouse(Component) {
  return class extends React.Component {
    render() {
      return (
        <Mouse render={mouse= > (
          <Component {. this.props} mouse={mouse} />)} / >); }}}Copy the code

13.2 Use Props instead of Render

It’s important to remember that Render Prop is called Render Prop because of the mode, and you don’t have to use a prop named Render to use this mode. In fact, any function prop that is used to tell components what to render is technically called a “Render prop.”

Although the previous example used Render, we could have simply used Children Prop!

<Mouse children={mouse= > (
  <p>The mouse position is {mouse.x}, {mouse.y}</p>)} / >Copy the code

Remember, Children Prop doesn’t really need to be added to the “Attributes” list of JSX elements. Instead, you can place it directly inside the element!

<Mouse>
  {mouse= > (
    <p>The mouse position is {mouse.x}, {mouse.y}</p>
  )}
</Mouse>
Copy the code

13.3 Precautions

If you create functions in the Render method, using Render Prop cancels out the benefits of using React.PureComponent. Because shallow comparisons of props always give false, and in this case each render will generate a new value for render prop.

In this case, each time the

renders, it generates a new function as a prop for

, thus simultaneously cancelling the effects of the

component inherited from the React.PureComponent!


class Mouse extends React.PureComponent {
  // Same code as above......
}

class MouseTracker extends React.Component {
  render() {
    return (
      <div>
        <h1>Move the mouse around!</h1>{/* This is not good! The value of each 'render' prop will be different. * /}<Mouse render={mouse= > (
          <Cat mouse={mouse} />)} / ></div>); }}Copy the code

To get around this problem, sometimes you can define a prop as an instance method, something like this:

class MouseTracker extends React.Component {
  // Define the instance method, 'this.renderthecat' always
  // When we use it in rendering, it refers to the same function
  renderTheCat(mouse) {
    return <Cat mouse={mouse} />;
  }

  render() {
    return (
      <div>
        <h1>Move the mouse around!</h1>
        <Mouse render={this.renderTheCat} />
      </div>); }}Copy the code

14 Error boundaries

JavaScript errors in part of the UI should not crash the entire app, and React 16 introduced a new concept called error boundaries to address this issue.

The error boundary is a React component that catches and prints JavaScript errors that occur anywhere in its child tree, and instead of rendering the broken child tree, it renders the alternate UI. Error bounds catch errors during rendering, in lifecycle methods, and in constructors throughout the component tree.

If either (or both) of the static getDerivedStateFromError() or componentDidCatch() lifecycle methods are defined in a class component, it becomes an error boundary. When an error is thrown, render the standby UI using static getDerivedStateFromError() and print the error message with componentDidCatch().

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Update state so that the next rendering can display the degraded UI
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // You can also report error logs to the server
    logErrorToMyService(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // You can customize the degraded UI and render it
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children; }}Copy the code

You can then use it as a regular component:

<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>
Copy the code

Error boundaries work like JavaScript’s Catch {}, except that they only apply to React components. Only class components can be error bound components. In most cases, you only need to declare the error boundary component once and use it throughout the application.

Note that an error boundary can only catch errors in its children, not in itself. If an error boundary cannot render an error message, the error bubbles to the nearest upper error boundary, similar to how catch {} works in JavaScript.

14.1 Where should error boundaries be placed?

The granularity of the error boundary is up to you, and you can wrap it around the topmost routing component and present the user with an “Something went wrong” error message, just as server-side frameworks often handle crashes. You can also wrap individual parts around error boundaries to protect the rest of your application from crashing.

14.2 New behavior for Uncaught Errors

Since React 16, any error not caught by the error boundary will cause the entire React component tree to be uninstalled.

14.3 Component stack Tracing

In a development environment, React 16 prints all errors that occur during rendering to the console, even if the application accidentally covers them up. In addition to error messages and JavaScript stacks, React 16 also provides component stack tracking. Now you can see exactly what error messages occur in the component tree.

14.4 about the try/catch

Try/catch is great but it only works for imperative code

However, the React component is declarative and specifies what needs to be rendered

14.5 About Event Handlers

Error bounds cannot catch errors within event handlers.

React does not require error boundaries to catch errors in event handlers. Unlike the Render and lifecycle methods, event handlers do not fire during rendering. So React still knows what needs to be displayed on the screen if they throw an exception.

If you need to catch errors inside event handlers, use plain JavaScript try/catch statements:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { error: null };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    try {
      // Perform the operation and throw if there is an error
    } catch (error) {
      this.setState({ error }); }}render() {
    if (this.state.error) {
      return <h1>Caught an error.</h1>
    }
    return <button onClick={this.handleClick}>Click Me</button>}}Copy the code

15 Performance Optimization

UI updates require expensive DOM operations, and React uses several clever techniques internally to minimize DOM operations.

15.1 Using the Production Version

When you need to benchmark your React application or run into performance issues, make sure you’re using a compressed production version.

15.2 Profiler

Profiler measures how often a React application is rendered and the “cost” of rendering once. Its purpose is to identify the parts of the application that render slowly, or that can be optimized like Memoization, and benefit from those optimizations.

Profiling adds additional overhead, so it can be disabled in production builds.

Profilers can be added anywhere in the React tree to measure the overhead of rendering that part of the tree. It requires two prop: the ID (string) and the onRender(function) callback called when a component in the component tree “commits” an update.

For example, to analyze the Navigation component and its descendants:

render(
  <App>
    <Profiler id="Navigation" onRender={callback}>
      <Navigation {. props} / >
    </Profiler>
    <Main {. props} / >
  </App>
);
Copy the code

The Profiler needs an onRender function as an argument. React calls this function when any component in the component tree contained in the profile “commits” an update. Its parameters describe what was rendered and how long it took.

function onRenderCallback(
  id, // The "ID" of the Profiler tree in which the commit occurred
  phase, // "mount" (rerender caused by the first load of the component tree) or "update" (rerender)
  actualDuration, // Committed The committed rendering time
  baseDuration, // Estimate the time required to render the entire subtree without memoization
  startTime, // React starts rendering time in this update
  commitTime, React COMMITTED time in this update
  interactions // This is the set of interactions
) {
  // Add up or record render times...
}
Copy the code

15.3 coordinate

When a component’s props or state changes, React determines whether an actual DOM update is necessary by comparing the latest returned element to the previously rendered element. React updates the DOM only when they are not equal. This process is called coordination.

At some point a node calls the Render () method of React, creating a tree of React elements. The same render() method returns a different tree the next time state or props is updated. React needs to use the difference between the two trees to determine how effectively to update the UI to keep the current UI in sync with the latest tree. React proposes a heuristic algorithm for O(n).

When comparing two trees, React first compares the root nodes of the two trees. Different types of root node elements have different shapes.

(1) Compare elements of different types

When the root node has a different type of element, React disassembles the existing tree and creates a new one. For example, when an element changes from to , from

to

, or from


When a tree is removed, the corresponding DOM node is also destroyed. The component instance will execute the componentWillUnmount() method. When a new tree is created, the corresponding DOM node is created and inserted into the DOM. Component instances will execute the componentWillMount() method, followed by the componentDidMount() method. All states associated with the previous tree are also destroyed.

Components below the root node are also uninstalled and their state is destroyed. For example, when the ratio is more variable than:

<div>
  <Counter />
</div>

<span>
  <Counter />
</span>
Copy the code

React destroys the Counter component and reloads a new one.

(2) Compare elements of different types

When you compare two React elements of the same type, React preserves the DOM node and only compares and updates the changed attributes. Such as:

<div className="before" title="stuff" />

<div className="after" title="stuff" />
Copy the code

By comparing the two elements, React knows that it only needs to change the className attribute on the DOM element.

When updating the style property, React updates only the properties that have changed. Such as:

<div style={{color: 'red'.fontWeight: 'bold'}} / ><div style={{color: 'green', fontWeight: 'bold'}} / >
Copy the code

By comparing the two elements, React knows that it only needs to change the color style on the DOM element, not the fontWeight.

After processing the current node, React continues to recurse on the child nodes.

(3) Compare component elements of the same type

When a component is updated, the component instance remains the same, so that state remains consistent across different renderings. React to update the component instance props to consistent with the latest element, and invoke the instance componentWillReceiveProps () and componentWillUpdate () method.

Next, the render() method is called, and the diff algorithm recurses over the previous result as well as the new one.

(4) Recurse the child nodes

By default, React iterates through lists of both child elements while recursively iterating through the child elements of a DOM node. When a difference occurs, a mutation is generated.

When adding an element at the end of the child element list, the change overhead is lower. Such as:

<ul>
  <li>first</li>
  <li>second</li>
</ul>

<ul>
  <li>first</li>
  <li>second</li>
  <li>third</li>
</ul>
Copy the code

React matches two

  • first
  • trees, then matches the second< li>second tree, and finally inserts the

  • third
  • tree of the third element.

    If implemented simply, inserting at the head of the list can be a performance drag and can be expensive. Such as:

    <ul>
      <li>Duke</li>
      <li>Villanova</li>
    </ul>
    
    <ul>
      <li>Connecticut</li>
      <li>Duke</li>
      <li>Villanova</li>
    </ul>
    Copy the code

    React will mutate for each child element instead of keeping the same

  • Duke
  • and

  • Villanova
  • subtrees complete. Inefficiencies in this case can cause performance problems.

    (5) Keys

    To address these issues, React supports the key attribute. When a child element has a key, React uses the key to match the child element of the original tree with the child element of the latest tree. The following example makes a previously inefficient conversion efficient after adding a key:

    <ul>
      <li key="2015">Duke</li>
      <li key="2016">Villanova</li>
    </ul>
    
    <ul>
      <li key="2014">Connecticut</li>
      <li key="2015">Duke</li>
      <li key="2016">Villanova</li>
    </ul>
    Copy the code

    React now knows that only elements with the ‘2014’ key are new; elements with the ‘2015’ and ‘2016’ keys are simply moved.

    The element you want to present may already have a unique ID, so the key can be extracted directly from your data. Finally, you can also use the element’s index in the array as a key. This strategy works well when elements are not reordered, but diff slows down once the order changes.

    Component state may encounter some problems when subscription-based components are reordered. Because component instances decide whether to update and reuse based on their key, if the key is a subscript, the order in which changes are made changes the current key, causing states of uncontrolled components (such as input fields) to tamper with each other and change unpredictably.

    (6)

    Keep in mind that the coordination algorithm is an implementation detail. React can re-render the entire application after each action, and the end result will be the same. In this context, rerendering means calling the Render method within all components, not that React will unload or load them. React will only decide how to merge differences based on the rules mentioned above.

    We regularly explore optimization algorithms to make common use cases perform more efficiently. In the current implementation, it is understood that a subtree can move between its siblings, but not anywhere else. In this case, the algorithm rerenders the entire subtree.

    React relies on exploratory algorithms, so performance suffers when the following assumptions are not met.

    1. The algorithm does not attempt to match subtrees of different component types. If you find yourself switching between two different types of components with very similar output, it is recommended to change them to the same type. In practice, we have encountered no such problems.
    2. The Key should be stable, predictable, and unique to the list. Unstable keys (such as those generated by math.random ()) cause many component instances and DOM nodes to be recreated unnecessarily, which can lead to performance degradation and loss of state in child components.

    15.4 shouldComponentUpdate

    This is a subtree of a component. In each node, SCU represents the value returned by shouldComponentUpdate, and vDOMEq represents whether the React elements returned are the same. Finally, the color of the circle indicates whether the component needs to be mediated.

    C2’s shouldComponentUpdate should return false. React does not render C2, and C4 and C5’s shouldComponentUpdate should not be called.

    For C1 and C3, shouldComponentUpdate returns true, so React needs to look down the child node. Here C6’s shouldComponentUpdate returns true, and React updates the DOM because the rendered element is different from the previous one.

    The last interesting example is C8. React needs to render this component, but since it returns the same React element as previously rendered, there is no need to update the DOM.

    As you can see, React only changes the DOM of C6. For C8, the render is skipped by comparing the React element to the render. For children of C2 and C7, render is not called due to shouldComponentUpdate. So they don’t need contrast elements either.

    In most cases, you can use react. PureComponent instead of shouldComponentUpdate. But it only does shallow comparisons, so if the props or the state are mutable in some way, shallow comparisons leave something out, and you can’t use it.

    class ListOfWords extends React.PureComponent {
      render() {
        return <div>{this.props.words.join(',')}</div>; }}class WordAdder extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          words: ['marklar']};this.handleClick = this.handleClick.bind(this);
      }
    
      handleClick() {
        // This part of the code is bad and buggy
        const words = this.state.words;
        words.push('marklar');
        this.setState({words: words});
      }
    
      render() {
        return (
          <div>
            <button onClick={this.handleClick} />
            <ListOfWords words={this.state.words} />
          </div>); }}Copy the code

    The problem is that PureComponent simply compares the values of old and new this.props. Words. Because the WordAdder handleClick method changes the same words array, the new and the old this.props. Words are still comparing the same array. Even though the words in the array have actually changed, the comparison results are the same. As you can see, the ListOfWords are not updated even though there are new words to render.

    The easiest way to avoid this problem is to avoid changing the value you are using for props or state. For example, the handleClick method above can be overridden with concat:

    handleClick() {
      this.setState(state= > ({
        words: state.words.concat(['marklar'])})); }Copy the code

    You can rewrite code in a similar way to avoid mutable objects. For example, we have an object called ColorMap. We want to write a method that sets colormap.right to ‘blue’. We can write this:

    function updateColorMap(colormap) {
      colormap.right = 'blue';
    }
    Copy the code

    To not change the original Object, we can use the object. assign method:

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

    15.5 Code Segmentation

    Packaging is a great technique, but as your application grows, so will your code package. This is especially true if you integrate large third-party libraries. You need to pay attention to the code contained in your code package so that it does not take too long to load because it is too large.

    Breaking up your app’s code can help you lazily load content that your current users want, which can significantly improve your app’s performance. While it doesn’t reduce the overall code volume of your application, you can avoid loading code that users never need, and reduce the amount of code that needs to be loaded during initial loading.

    (1) import()

    Before use:

    import { add } from './math';
    
    console.log(add(16.26));
    Copy the code

    After use:

    import("./math").then(math= > {
      console.log(math.add(16.26));
    });
    Copy the code

    (2) React.lazy

    The react. lazy function allows you to render dynamically imported components in the same way as regular components.

    Before use:

    import OtherComponent from './OtherComponent';
    Copy the code

    After use:

    const OtherComponent = React.lazy(() = > import('./OtherComponent'));
    Copy the code

    This code will automatically import the package containing the OtherComponent when the component is first rendered.

    (3) Exception capture boundary

    It triggers an error if the module fails to load (such as a network problem). You can handle these situations with the Error boundaries technique to demonstrate a good user experience and manage recovery.

    (4) Code segmentation based on routing

    Deciding where to introduce code splitting can be tricky. You need to make sure that the location you choose splits the code package evenly without affecting the user experience.

    A good place to start is with routing. Most web users are used to having a load switch between pages. You can also choose to re-render the entire page so that your users don’t have to interact with other elements on the page at the same time.

    import React, { Suspense, lazy } from 'react';
    import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
    
    const Home = lazy(() = > import('./routes/Home'));
    const About = lazy(() = > import('./routes/About'));
    
    const App = () = > (
      <Router>
        <Suspense fallback={<div>Loading...</div>} ><Switch>
            <Route exact path="/" component={Home}/>
            <Route path="/about" component={About}/>
          </Switch>
        </Suspense>
      </Router>
    );
    Copy the code

    (5) Named export

    React.lazy currently only supports default exports. If you want the imported module to use named exports, you can create an intermediate module to re-export as the default module.

    99 Other Contents

    Often, multiple components need to reflect the same changing data, and we recommend promoting the shared state to the nearest common parent. Let’s see how it works.

    Status: https://react.docschina.org/docs/lifting-state-up.html

    React has a very powerful combination mode. We recommend using composition rather than inheritance to achieve code reuse between components.

    Combination VS inheritance: https://react.docschina.org/docs/composition-vs-inheritance.html

    The idea of building applications and pulling components apart

    The React philosophy: https://react.docschina.org/docs/thinking-in-react.html

    Accessibility accessibility

    Barrier-free auxiliary function: https://react.docschina.org/docs/accessibility.html

    Collaborate with third-party libraries

    With the third party libraries: https://react.docschina.org/docs/integrating-with-other-libraries.html

    React without using JSX

    Do not use the JSX React:https://react.docschina.org/docs/react-without-jsx.html

    Static type checking

    Static type checking: https://react.docschina.org/docs/static-type-checking.html

    Strict mode

    Strict mode: https://react.docschina.org/docs/strict-mode.html

    Use PropTypes for type checking

    Using PropTypes type check: https://react.docschina.org/docs/typechecking-with-proptypes.html

    Web Components

    Web Components:https://react.docschina.org/docs/web-components.html

    FAQ

    FAQ:https://react.docschina.org/docs/faq-ajax.html