Reputation: 18545
The code below pass jsx from parent to child;
The problem is that the reference row.descBox
is undefined, maybe due to jsx in parent.js
is not yet run;
how should I make it point to the span
element?
This is Parent.js
import { useEffect, useRef, useState } from "react";
import "./styles.css";
import Child from "./Child";
export default function Parent() {
const taskRefs = useRef([]);
const [cellContent, setCellContent] = useState([]);
useEffect(() => {
const cellContent = [
{
content: (
<>
<h1>
<span
ref={(el) => {
taskRefs.current[0] = el;
}}
>
inside span
</span>
</h1>
</>
),
descBox: taskRefs.current[0]
}
];
setCellContent(cellContent);
}, []);
return <Child cellContent={cellContent} />;
}
This is Child.js
import { useEffect, useState } from "react";
import "./styles.css";
export const Child = ({ cellContent }) => {
return (
<div className="App">
{cellContent.map((row, i) => {
{
console.log(row.descBox);//this is null!
return <div key={i}>{row.content}</div>;
}
})}
</div>
);
};
export default Child;
Try the code at codesandbox
Upvotes: 0
Views: 53
Reputation: 12920
The callback to set the ref inside the stored jsx won't be run until the component is mounted in the DOM and logging inside the map()
is before that happens (you haven't even returned it yet). You'll need to log in a useEffect
in order to see it set. I've added log
calls to each step in the snippet below to illustrate the order.
As a side note, can't set descBox
to taskRefs.current[0]
as it will then be locked as undefined
. You will need to assign it either the ref object taskRefs
or the nested array assigned to taskRefs.current
as either of these will be updated by reference when the ref is finally set).
const { useState, useEffect, useRef } = React;
function App() {
const taskRefs = useRef([]);
const [cellContent, setCellContent] = useState([]);
useEffect(() => {
const cellContent = [
{
content: (
<span
ref={(el) => {
console.log("setting ref");
taskRefs.current[0] = el;
}}
>
inside span
</span>
),
descBox: taskRefs
}
];
setCellContent(cellContent);
}, []);
return <Child cellContent={cellContent} />;
}
function Child({ cellContent }) {
useEffect(() => {
if (cellContent.length) {
console.log("inside useEffect. Ref:",cellContent[0].descBox.current[0]);
} else {
console.log('first render.');
}
});
return (
<div className="App">
{cellContent.map((row, i) => {
console.log("inside map. Ref:", row.descBox.current[0]);
return <div key={i}>{row.content}</div>;
})}
</div>
);
};
const container = document.getElementById('root');
const root = ReactDOM.createRoot(container);
root.render(<App />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<div id='root'></div>
Upvotes: 1