UseImperativeHandle
You can't use ref attributes on function components because they have no instances:
import React, { Component } from 'react'; function MyFunctionComponent() { return <input /> } class Parent extends { constructor(props) { super(props); = (); } render() { return ( <MyFunctionComponent ref={} /> ); } }
If you need to use ref, you should convert the component into a class, just like when you need to use a lifecycle hook or state.
Anyway, you can use the ref attribute inside the function component, as long as it points to a DOM element or class component:
function CustomTextInput(props) { // This must be declared so that ref can refer to it let textInput = (); function handleClick() { (); } return ( <div> <input type="text" ref={textInput} /> <input type="button" value="Focus the text input" onClick={handleClick} /> </div> ); }
In the following example, MyFunctionComponent uses , to get the ref passed to it, and forward it to the DOM button it renders:
const MyFunctionComponent = ((props, ref) => ( <button ref={ref}> {} </button> )) class Parent extends { constructor(props) { super(props); = (); } componentDidMount() { () } render() { return ( <MyFunctionComponent ref={} /> ); } }
The second parameter ref only exists when defining components using . Regular functions and class components do not receive ref parameters, and ref does not exist in props.
useImperativeHandle
useImperativeHandle allows you to customize the instance values exposed to the parent component when using ref. useImperativeHandle should be used with forwardRef:
const MyFunctionComponent = ((props, ref) => { const inputRef = useRef(); useImperativeHandle(ref, () => ({ focus: () => { (); } })); return ( <input ref={inputRef} /> ) }) class Parent extends { constructor(props) { super(props); = (); } componentDidMount() { () } render() { return ( <MyFunctionComponent ref={} /> ); } }
When using useImperativeHandle, the parent component did not get the child component method for the first time
Background requirements
A tab has two buttons A and B. A is selected by default. When B is clicked, the corresponding chart of B needs to be displayed. Considering that B's chart has been initialized when the page is loaded, the resize method of the chart is called when clicking B. Since the chart in the tab is written in the child component, the parent component calls the child component method through useImperativeHandle. The React version "react": "^18.1.0", the code is as follows
Parent component:
const childRef = useRef() const item = [{ name: 'XXXX', content: <RunningRecord cRef={childRef} />, handClick: ?.resizeChart }] return <> …… <li onClick={() => { setTimeout(() => { ('~~',) ?.() }, 200) }} key={}> {} </li> …… <RunningRecord cRef={childRef} /> </>
Subcomponents:
function RunningRecord({ cRef }) { …… useImperativeHandle(cRef,()=>({ resizeChart:()=> {dosomething……} }))
question
This is written in the local development mode to run normally, but in the production environment, the parent component cannot get the child component for the first time loading. Tab needs to switch to A and then B. The reason is guessed that in a production environment, the parent component binds the exposed method of the child component to the click event in the UI, and the child component is initialized late, and the event is not transmitted back after the initial completion.
This guess may not be accurate, please add to those who know it.
Solution
In the parent component, put the process of assigning the child component in useEffect, do not write the dependency parameters (not an empty array without dependencies), and then run, everything is normal.
const usageRecordData = [{ name: 'XXXX', content: <RunningRecord cRef={childRef} />, }] useEffect(() => { usageRecordData[1].handClick = ?.resizeChart })
The above is personal experience. I hope you can give you a reference and I hope you can support me more.