preface

Because React’s functional components are easy to use (as opposed to the Class component), I’ll focus on using functional components to run development. In this blog series, I’m going to share what I’ve learned about the Hook apis. The Hooks series includes the following:

  • useState
  • useReducer
  • useContext
  • useEffect
  • useMemo
  • useRef
  • Customize the Hook

What is useRef

UseRef returns a mutable ref object whose.current property is initialized as the passed parameter (initialValue). The ref object returned remains constant throughout the life of the component.

This ref object has only one current property, so you save something inside, and its address stays the same.

A simple example

import React, { useRef } from "react";
export default function App() {
  const r = useRef(0);
  console.log(r);
  const add = () = > {
    r.current += 1;
    console.log(`r.current:${r.current}`);
  };
  return (
    <div className="App">
      <h1>R current: {r.c urrent}</h1>
      <button onClick={add}>Click on the + 1</button>
    </div>
  );
}
Copy the code

I set an R on top to save the result of useRef and log it out, so let’s see what’s inside

>  {current: 0}
Copy the code

Inside is acurrentProperty that holds the 0 that I passed in.

UseRef changes do not actively render the page

Let’s click on the button at the topcurrent+1, you can see that the page is not actively rendered, but newcurrentThe value of theta has become 1

Note When the value of the current property changes, the page does not change as useState or useReducer does. How do you solve this problem? So let’s get to the bottom of this

summary

  • We use theuseCurrentThe incominginitialValue, it can be concluded that it becomes an inclusioncurrentProperty object,currentThe corresponding value of the property isinitialValue
  • According to the React documentation, you know that the address of this object does not change from beginning to end
  • UseRef changes do not actively render the page

Application to solve

Let’s simulate a ComponentDidUpdate using useRef and useEffect

import React, { useEffect, useRef, useState } from "react";
export default function App() {
  const r = useRef(0);
  const [n, setN] = useState(0);
  useEffect(() = > {
    r.current += 1;
    if (r.current > 1) {
      console.log("r.current:" + r.current);
      console.log("n:"+ n); }});return (
    <div className="App">
      <h1>n:{n}</h1>
      <h1>r.current{r.current}</h1>
      <button
        onClick={()= > {
          setN(n + 1);
        }}
      >
        {" "}
        +1
      </button>
    </div>
  );
}
Copy the code

Render the result for the first time

When you click the +1 button,You’ll see that the code executes, so that you can implementComponentDidUpdate

Current has changed

In the above code, it can be seen that the current on the page has changed. This is because our state has changed, so the new current has also been rendered.

You can think of react as the mechanism:

There’s a single current, I don’t care.

The state has changed. Update the page. Wait, take this current with you.

So we can manually set current changes to actively trigger page updates by setting an impractical state.

If you are careful, you will see that the rendered value on the page is not the latest current value. The reason for this is that Effect is always executed after Render, when current has just become the latest, and React doesn’t just update the view again for Current. So the page is still old Current. And so that confirms what we started with

UseRef changes do not actively render the page

We don’t normally display current in views, but the above example just wants you to notice the subtle relationship between current changes and views

summary

Since current does not actively render pages, it is best to manually set current to be updated by the view along with a fake state.

Have to say forwardRef

ref

On hook components, you cannot use ref directly, and the official website does not even recommend using ref on class components. But we might use a ref, which is mostly used to pass to a child component and get the DOM of that child component. Here is the official documentation Refs and function components

When to use Refs

Here are a few situations where refs are appropriate:

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

Interpreting official examples

function CustomTextInput(props) {
  // textInput must be declared here so that ref can reference it
  const textInput = useRef(null);// Create an object containing the current property

  console.log(textInput);
  function handleClick() {
    textInput.current.focus();
  }

  return (
    <div>
      <input type="text" ref={textInput} />// Attach to the internal DOM<input type="button" value="Focus the text input" onClick={handleClick} />
    </div>
  );
}
Copy the code

Note that fowardRef is not used in this example, because ref is not used on child components, but inside function components

We can see that by attaching a REF to a React element, we can retrieve its DOM.

There are two steps

  • useRefTo create arefobject
  • ref={xx}hangreactOn the element

Then you can use this element. The official example is to take the element and focus it by clicking the button. We now have a rough idea of how ref is used.

Use ref on child components

The above method cannot be used directly on child components, as you might write

<Child ref={textInput} />
Copy the code

Instead of getting the DOM of the subcomponent, we need to use the forwardRef

function CustomTextInput(props) {
  // textInput must be declared here so that ref can reference it
  const textInput = useRef(null);

  console.log(textInput);
  function handleClick() {
    textInput.current.focus();
  }
  return (
    <div>
      <Child ref={textInput} />//** still uses ref to pass **<input type="button" value="Focus the text input" onClick={handleClick} />
    </div>
  );
}
const Child = forwardRef((props, ref) = > {  See me / / * * * *
  return <input type="text" ref={ref} />;//** see if I hang it on the corresponding DOM **
});
Copy the code

Parent = (ref={ref}); parent = (ref={ref}); parent = (ref={ref})

current: <input type=”text”></input>

The DOM element of the child component is retrieved.

summary

We learned from the above example that using ref inside a function component is different from using ref on a child component

  • If you want to use it inside a function, just create a post-mount ref attribute to the React element.
  • If you want to use it on a child component, you need to use it in addition to the steps aboveforwardRefWrap the function of the child component, and then pass in the second argumentref, and finally mountrefYou can get the DOM normally.

conclusion

We now know that useRef will generate an object with the current property, which will hold the address unchanged for the entire react rendering life, and we can use it to do some things.

For example, create a global invariant data that simulates ComponentDidUpdate

You can also mount it to the React element and get the ELEMENT’s DOM. (Use refs and subcomponents directly with the forwardRef)

github

Finally, I would like to promote the Github blog that I maintain for a long time

1. From learning to summary, record important knowledge points of the front-end, including in-depth Javascript, HTTP protocol, data structure and algorithm, browser principles, ES6, front-end skills, etc.

2. There is a directory in the README to find relevant knowledge points.

If it is helpful to you, welcome star and follow.

The address is here