In actual react project development, it is sometimes necessary to call the child component method in the parent component, and the child component is generated in a loop. Although this does not conform to the react design philosophy, there is a requirement for this in development. Here are two solutions:
The first way is to useuseRef/useImperativeHandle/forwardRef
:
useRef
Initialize to an array- Set in child component loop generation
childRefs.current[item.id] = ref;
- Child components are required
forwardRef
Wrap it up,(useconnect
Subcomponents of the package need to be added{ forwardRef: true }
See you,here) - use
useImperativeHandle
To export the child component, note the second argument to the child component
Here is the simplest code and associated comments:
// Parent component:
import React, { useRef } from 'react';
import ChildComp from './ChildComp';
function App() {
const arr = [
{
id: 1.name: '🍎'}, {id: 2.name: '🍌'}, {id: 3.name: '🍊',},];// useRef is initialized to an array
const childRefs = useRef<any> ([]);return (
<div className="App">
{arr.map((item) => (
<ChildComp/ / ⚠ ️ attentionrefIt could be empty so I'm going to add a judgment hereref={(ref)= > {
if (ref) {
childRefs.current[item.id] = ref;
}
}}
data={item}
key={item.id}
/>
))}
<button
onClick={()= >{childRefs. Current && childRefs. Current. ForEach ((childRef: any) = > {/ / call the method that all subcomponents childRef. ExportChildMethod (); / / get all subcomponents the value of the console, log (childRef. ExportChildValue ()); }); Console. log(childrefs.current && childrefs.current [1].exportChildValue()); }} > Invoke the child component's methods</button>
</div>
);
}
export default App;
/ / child component
import React, { forwardRef, useState, useImperativeHandle } from 'react';
// the component wrapped with the forwardRef gets a ref argument
const Child = (props: any, ref: any) = > {
const { data } = props;
const [childNum, setChildNum] = useState<number> (0);
UseImperativeHandle exports the methods used by the parent component
useImperativeHandle(ref, () = > ({
exportChildMethod: () = > {
childMethod();
},
exportChildValue: () = > {
returnchildNum; }}));const childMethod = () = > {
console.log(`log from child--${data.name}`);
};
return (
<div>
<p>{data.name}</p>
<p>{childNum}</p>
<button
onClick={()= > {
setChildNum(childNum + 1);
}}
>
child add
</button>
</div>
);
};
// Need to use forwardRef wrap
export default forwardRef(Child);
Copy the code
The second way is not to use ituseRef/forwardRef/useImperativeHandle
, the idea is that props changes the method used to trigger a child component:
- The parent component sets a number of milliseconds
ms
Is empty - The parent component triggers the action, setting the number of milliseconds
ms
fornew Date().getTime()
- the
ms
Pass to a child component - Child components in the
useEffect
The dependencems
The value of thems
Change the function within the trigger child
import React from 'react';
import ChildComp from './ChildComp';
function App() {
const arr = [
{
id: 1.name: '🍎'}, {id: 2.name: '🍌'}, {id: 3.name: '🍊',},];const [ms, setMs] = useState<number | undefined> ();const emitChildMethod = () = > {
setMs(new Date().getTime());
};
return (
<div className="App">
{arr.map((item) => (
<ChildComp ms={ms} data={item} key={item.id} />
))}
<div>
<button onClick={emitChildMethod}>Invoke methods of child components</button>
</div>
</div>
);
}
export default App;
/ / child component
import React, { useState, useEffect } from 'react';
const Child = (props: any) = > {
const { data } = props;
const [childNum, setChildNum] = useState<number> (0);
useEffect(() = > {
// Make a judgment call here
if (ms) {
childMethod();
}
}, [ms]);
const childMethod = () = > {
console.log(`log from child--${data.name}`);
};
return (
<div>
<p>{data.name}</p>
<p>{childNum}</p>
<button
onClick={()= > {
setChildNum(childNum + 1);
}}
>
child add
</button>
</div>
);
};
export default Child;
Copy the code
To summarize
- Both approaches are a last resort and break the design pattern for single data flows
- It is also bad for code debugging and business sorting
- However, it has certain advantages in modifying old code and adding new functions