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.createRef
Create one that can be attached to the React element via the ref attributeref. - useRef:
useRef
A ref object has been returnedcurrent
Properties.
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: