This is the 23rd day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

What values can be passed to the ref attribute

CreateRef () and React. UseRef () create objects; Callback function, string

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.

String refs

The string refs used to be popular in class Component, but the use of passing strings is now obsolete

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.

The callback refs

export default function IndexPage() { const [count, setCount] = useState(0); const add = useCallback(() => { setCount((count) => { return ++count; }); } []); return ( <div className=" p-12"> <div>callback refs </div> <div className="w-32 inline-block mr-2"> <Input value={count}></Input> </div> <Button ref={(dom)=>console.log(dom)} icon={<PlusOutlined />} className="ml-8" onClick={add} > add </Button> </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.

In addition, this callback is called twice for each update to the component, passing null the first time:

CreateRef and useRef

Definition:

  • createRef:React.createRefCreate one that can be attached to the React element via the ref attributeref.
  • useRef: useRefA ref object has been returnedcurrentProperties.

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

Both can be passed to a ref and get the DOM, but let’s look at the differences:

The difference between

  • Grammatical differences between

CreateRef cannot be passed an initial value, and the current property is read-only. UseRef does not.

  • The underlying difference

First maintain two sets

export const  uRefs = new Set()
export const cRefs = new Set()
Copy the code

Each update puts the objects created by useRef and createRef into these two sets:

import { uRefs, cRefs } from './data'; export default function IndexPage() { const [count, setCount] = useState(0); const uRef = useRef<any>(); const cRef = createRef<any>(); const uRef1 = useRef(0); const cRef1 = createRef(); const add = useCallback(() => { setCount((count) => { return ++count; }); } []); useEffect(() => { console.log('update') uRefs.add(uRef); cRefs.add(cRef) console.log('uRef', uRefs) console.log('cRef', cRefs) }); Return (<div className=" p-12"> <div>createRef and useRef </div> <div className=" W-32 inline-block MR-2 "> use ref: <Input ref={uRef} value={count}></Input> </div> <div className="w-32 inline-block"> create ref: <Input ref={cRef} value={count}></Input> </div> <Button icon={<PlusOutlined />} className="ml-8" onClick={add}> add </Button> </div> ); }Copy the code

After two updates:As you can see, createRef recreates the ref object with each update and sets the current of the old ref object to NULL.

UseRef, on the other hand, is always the same object in multiple updates. This is how the definition is interpreted:

Persists throughout the life cycle of a component

So when you have a complex object to maintain that doesn’t involve rendering, using useRef can avoid the performance cost of creating that object with frequent updates.

ForwardRef and useImperativeHandle

forwardRef

The React. ForwardRef creates a React component that forwards the ref properties it receives to another component in its component tree.

There are two main scenarios for this API: forwarding refs and using refs on function Components (which is essentially forwarding refs).

By “forwarding”, you mean that the component you encapsulate supports the REF attribute and exposes a DOM in that component (not necessarily the root DOM of that component) through ref.

Alternatively, if the Function Component cannot use ref (because it has no component instance), this API can be used for forwarding

You may not use the ref attribute on function components because they don’t have instances.

const FancyButton = React.forwardRef((props, ref) => ( <button ref={ref} className="FancyButton"> {props.children} </button> )); // You can now get a ref directly to the DOM button: const ref = React.createRef(); <FancyButton ref={ref}>Click me! </FancyButton>;Copy the code

useImperativeHandle

This API works with the forwardRef to make the exposed Ref object perform some of the functions it defines

UseImperativeHandle allows you to customize the instance value exposed to the parent component when using a ref. In most cases, imperative code like ref should be avoided. UseImperativeHandle should be used with the forwardRef:

function FancyInput(props, ref) {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));
  return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
Copy the code

Example: ANTD3 is submitted outside the form

Talk is cheap.

In ANTD3, the Form object does not have a Submit attribute, so to trigger the form’s onSubmit externally (such as a popover), you need to combine useImperativeHandle and useImperativeHandle

Form: Expose the submit method with useImperativeHandle, which calls onSubmit directly.

You can also expose more apis, such as beforeSubmit, afterSubmit, onError, and form objects.

const Demo = React.forwardRef((props: FormComponentProps, ref)=>{ const { getFieldDecorator, validateFields, } = props.form; const onSubmit = (e? : FormEvent)=>{ e? .preventDefault(); validateFields((e, V)=> {})} useativeHandle (ref,()=>({submit:onSubmit})) return <Form onSubmit={onSubmit}> < form.item label=" name "> {getFieldDecorator('name',{rules:[{required:true,message:' please enter username '}]})(<Input placeholder="user name"/>)} </ form.item > < form. Item label=" address" > {getFieldDecorator('address')(<Input placeholder="user address"/>)} </ form. Item> </Form>}) const DemoForm = Form.create()(Demo)Copy the code

Modal: Creates the ref and passes in the component because it is form. create, so you need to pass in the wrappedComponentRef as documented

When you click ok, call ref.current. Submit, which triggers validation of the form.

const DemoModal = () => {
  const ref = useRef<any>()
  return <Modal title="demo" visible={true} onOk={()=>{ref.current.submit()}}>
    <DemoForm wrappedComponentRef={ref}></DemoForm>
  </Modal>
}
Copy the code

Effect: