Reputation: 1219
There's an array of react components inside parent component. On some event on parent component I'd like to run through the array of child components and call a method for each. How can I achieve that? It seems it doesn't work as in vanilla JS where you have an instance for the class and simply call a method. So here's the simplified code:
const Item = props => {
const value = () => 'result!';
return (
<div></div>
)
}
const App = props => {
const items = props.items.map(item => <Item key={uuid()} item={item} />)
const run = e => {
items.map(item => console.log(item.value()))
}
return (
<button onClick={run} type="button">Run!</button>
)
}
const items = [
'Lorem ipsum dolor sit amet',
'consectetur adipiscing elit'
];
ReactDOM.render(<App items={items} />, document.querySelector("#app"))
I've created a jsfiddle with this code - https://jsfiddle.net/jkLq26pg/37/
On the 11th string the method value() is called and it raises an error. But logging item.props
works and outputs props for each item. Why methods are not called?
Please provide me with an advice how to make it work.
Upvotes: 3
Views: 3119
Reputation: 13702
In your case you have to map thru the array and attach a ref using callback ref. Render the child component using forwardRef and use the useImperativeHandle hook to expose your function to the parent.
Code Snippet
const Item = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
value: () => "result!"
}));
return <div ref={ref} />;
});
const itemsz = ["Lorem ipsum dolor sit amet", "consectetur adipiscing elit"];
const App = props => {
const ref = useRef({});
const items = itemsz.map((item, index) => {
return (
<Item
ref={r => (ref.current[index] = r)}
key={index}
item={item}
/>
);
});
const run = e => {
items.map((item, index) => console.log(ref.current[index].value()));
};
return (
<>
<h3>click run and see console log</h3>
<button onClick={run} type="button">
Run!
</button>
{items}
</>
);
};
Note - Try avoiding this kind of pattern.
Upvotes: 3
Reputation: 2752
One way to solve this problem is to write useEffect
and call your item.value()
logic inside that useEffect
. Your function will then be automatically called once your list has mounted to the DOM. That is probably the right place to call your function because your list would have rendered inside the DOM and side effects can then be handled.
const Item = props => {
const value = () => 'result!';
// Handle your side effects here
useEffect(() => {
value();
}, []);
return (
<div></div>
)
}
This useEffect will work after a component will mount into DOM Node. You can always put your function in one of the lifecycle methods in class based components or hooks in functional components and call them from there according to your situation.
Upvotes: 0