Welcome toTencent Cloud + community, get more Tencent mass technology practice dry goods oh ~

This article was published in cloud + Community column by Zhihang

TL; DR

Use the state and lifecycle of the Classes Components in the React function. There is no need to switch back and forth between mixin, function component, HOC component and render props, which makes the function of function component more realistic and more convenient for us to realize the separation of business logic code and the reuse of components in business.

This article covers hooks in the following ways

What are the Hooks addressing? The Hooks API is about Hooks and how to use them

What problem are 💡Hooks solving

React has been addressing the problem of separating business logic code and reusing related business logic within components.

Typically, we organize large UIs on our pages into small, independent UIs through components and top-down data flows, enabling component reuse. But it is often difficult to break into a complex component for reuse because the logic of the component is stateful and cannot be extracted from the functional component. This is especially common with animations and forms, where we can mess up a component by connecting to an external data source and then hoping to perform more operations within the component:

  • It is difficult to reuse and share state-related logic in components, resulting in many large components
  • Logically complex components are difficult to develop and maintain. When our component needs to deal with multiple unrelated localstates, each lifecycle function may contain a variety of unrelated logic.
  • Complex patterns such as render items and advanced components.
  • Due to business changes, functional components had to be changed to class components.

That’s where the Hooks come in. Hooks allow us to organize the logic inside a component into a reusable, isolated module.

To illustrate the point, here are two images from @Sunil Pai:

The React Hooks experience is the implementation of the React philosophy inside components. Previously, we only directly embodied the React philosophy in components and components, that is, clear data flow and composition form. The logic within components can be reused, without the layers of nesting brought by HOC, and without the drawbacks of mixins.

An introduction to the 💡Hooks API and how to use Hooks

Dan_abramov introduced usto three key apis for hooks at the conference: State hooks, Effect Hooks, and Custom hooks.

📌 state Hooks (useState)

The useState method brings local state to our function component, which takes a value for the initial state and returns a pair of variables. Let function components have their own components.

First, what if we wanted to implement a button +1 component with classes Component?

import React from 'react';

class Example extends React.Component {
    constructor(props) {
        super(props);
        this.state = {count: 0};
        this.clickBtn = this.clickBtn.bind(this);
    }
    clickBtn = (a)= > {
        this.setState({
            count: this.state.count + 1;
        });
    }
    return (
        <div>
            <p>You clicked {this.state.count} times</p>
            <button onClick={this.clickBtn}>
                Click me
            </button>
        </div>
    );
}
Copy the code

What about using useState? You can see it very clearly.

// A simple click count
import { useState } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={()= > setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
Copy the code

📌 Effect Hooks (useEffect)

Fangfa is used by Effect Hooks to handle actions that have side effects. This example uses FangFA to listen for window width changes

import { useState } from 'react';

function windowWidth() {
    const [width, setWithd] = useState(window.innerWidth);
    useEffect((a)= > {
        const handleResize = (a)= >{
            setWidth(window.innerWidth);
        }
        window.addEventListener('resize', handleResize);
    });
    return (
        <p> window width is {width}</p>)}Copy the code

UseEffect can be passed in as a second operation to avoid the loss of performance, bypassing the change if the member variable in the second parameter array has not changed. How to pass in an empty array, so the effect is only executed when the component is mounted and unmounted.

import { useState } from 'react';

function windowWidth() {
    const [width, setWithd] = useState(window.innerWidth);
    useEffect((a)= > {
    const handleResize = (a)= >{
        setWidth(window.innerWidth);
    }
    window.addEventListener('resize', handleResize);
    }, [width]); // width does not change
    return (
        <p> window width is {width}</p>)}Copy the code

UseEffect can also perform cleanup operations such as unsubscribe by having a function return a function

import { useState } from 'react';

function windowWidth() {
  const [width, setWithd] = useState(window.innerWidth);

  useEffect((a)= > {
    const handleResize = (a)= >{
        setWidth(window.innerWidth);
    }
    window.addEventListener('resize', handleResize);

    return (a)= > {
        // Cancel listening for window width changes
        window.removeEventListener('resize'); }});return (
      <p> window width is {width}</p>)}Copy the code

As shown above, built-in React Hooks like useState and useEffect act as basic building blocks. We can use them directly in components, or we can combine them into custom hooks, such as useWindowWidth. Using custom Hooks feels like using the React built-in API.

📌Custom Hooks Custom components

Following the code that listens to the window size above, we continue with custom hooks to show how react hooks make logic within components reusable.

Talk is cheap, show me the code.

// a component that displays the current window size
function responsiveComponent(){
   // custom hooks
   const width = useWindowWidth(); 
   return (
       <p>The width of the current window is {width}</p>)}Copy the code

The code above is just a few lines long, and it makes it very clear that it is there to listen for changes to the current window. That is the goal of Hooks – to make components truly declarative, even if they contain state and side effects.

Let’s take a look at how to implement this custom Hook. We use the React local state to keep the current window width and use side effects to set the state when the window is resized

import { useState, useEffect} from 'react';
// custom hooks to listen window width change
function useWindowWidth(){
    const [width, setWidth] = useState(window.innerWidth);

    useEffect((a)= > {
        const handleResize = (a)= >{
            setWidth(window.innerWidth);
        }
        window.addEventListener('resize', handleResize);
    }, [width]); // width does not change

    return width;
}
Copy the code

[Example of online editing]

âš¡ React Hooks rules

Hooks are JavaScript functions, but they impose two additional rules:

  • Hooks can only be called at the top level. Do not call hooks in loops, conditions, or nested functions.
  • Call Hooks only from the React feature component. Do not call a Hook from a regular JavaScript function. (There is another place to call Hooks — your own custom Hooks.)

🔌 other Hooks

There are some built-in hooks that are not commonly used. For example, useContext allows you to subscribe to the React context without introducing nesting:

function Example() {
  const locale = useContext(LocaleContext);
  const theme = useContext(ThemeContext);
  // ...
}
Copy the code

An interesting repository, react-Use, contains a lot of interesting custom hooks

How do 👀hooks work

React-rex-not-magic -just- Arrays

React hooks are just an array, not magic.

How to implementuseState()methods

Let’s use an example here to demonstrate how the implementation of state hooks works.

Let’s start with a component:

function RenderFunctionComponent() {
  const [firstName, setFirstName] = useState("Rudi");
  const [lastName, setLastName] = useState("Yardley");

  return (
    <Button onClick={()= > setFirstName("Fred")}>Fred</Button>
  );
}
Copy the code

The idea behind the hooks API is that you can return a setter function as a second entry in the hook function, and the setter will control the state managed by the hook.

So what does React have to do with this?

Let’s see how this works inside React. The following can be used to render specific components in an execution context. This means that the data stored here is outside of the component being rendered. This state is not shared with other components, but it remains within the scope that specific components can be rendered later.

1) initialization

Create two empty arrays: setters and state

Set the cursor to 0

Initialize: two empty arrays with Cursor 0

2) First render

Run component functionality for the first time.

Each useState() call, when first run, pushes the setter function (bound to the cursor position) to the setter array, and then pushes some state to the state array.

First render: Item written to array as cursor increment.

3) Subsequent rendering

Each subsequent rendering resets the cursor and only reads these values from each array.

Subsequent render: Items read from the array are cursor increments

4) Event handling

Each setter has a reference to its cursor position, so by triggering a call to any setter, it changes the state value for that position in the state array.

Setters “remember” their index and set memory based on it.

UseState functions are implemented through pseudocode

Here is an example of code to demonstrate the implementation:

let state = [];
let setters = [];
let firstRun = true;
let cursor = 0;

function createSetter(cursor) {
  return function setterWithCursor(newVal) {
    state[cursor] = newVal;
  };
}

// Pseudo-code implementation of useState
export function useState(initVal) {
  if (firstRun) {
    state.push(initVal);
    setters.push(createSetter(cursor));
    firstRun = false;
  }

  const setter = setters[cursor];
  const value = state[cursor];

  cursor++;
  return [value, setter];
}

// Simulate using useState
function RenderFunctionComponent() {
  const [firstName, setFirstName] = useState("Rudi"); // cursor: 0
  const [lastName, setLastName] = useState("Yardley"); // cursor: 1

  return (
    <div>
      <Button onClick={()= > setFirstName("Richard")}>Richard</Button>
      <Button onClick={()= > setFirstName("Fred")}>Fred</Button>
    </div>
  );
}

// Simulate Reacts rendering cycles
function MyComponent() {
  cursor = 0; // Reset the cursor position
  return <RenderFunctionComponent />; // render } console.log(state); // Pre-render: [] MyComponent(); console.log(state); // Render first: ['Rudi', 'Yardley'] MyComponent(); console.log(state); // Next render: ['Rudi', 'Yardley'] // Click the 'Fred' button console.log(state); // After click: ['Fred', 'Yardley']Copy the code

conclusion

Hooks are in the early stages, but give us a good idea of the logic to reuse components, as you can see in React-16.7.0-alpha. 0.

Machine learning in action! Quick introduction to online advertising business and CTR knowledge

This article has been authorized by the author to Tencent Cloud + community, more original text pleaseClick on the

Search concern public number “cloud plus community”, the first time to obtain technical dry goods, after concern reply 1024 send you a technical course gift package!

Massive technical practice experience, all in the cloud plus community!