I have a child component, it looks through and creates Canvas elements in the DOM, then useEffect() draws things to these Canvases:
import { useEffect } from "react";
function Table(props) {
console.log(">> In Table, props is ", props);
useEffect(() => {
console.log(">> in useEffect ");
// prepare the data to render here and render to the multiple HTML Canvases in the DOM
}, []);
const options = [
{ value: 0, label: "1" },
{ value: 1, label: "2" }
];
const onChannelXChange = (option) => {
console.log("1. send the change back to the parent");
let change = {
type: "ChannelIndexChange",
// TODO need to get the plot here
plotIndex: 0,
channel: "x",
value: option.value,
};
props.parentCallback(change);
};
return (
<table className="workspace">
<tbody>
<tr key={`tr-${fileIndex}`}>
{props.workspaceState.plots.map((plot, plotIindex) => {
return (
<td key={`td-${plotIindex}`}>
<div>
<canvas
className="canvas"
id={`canvas-${fileIndex}-${plotIindex}`}
width="400"
height="400"
/>
<Dropdown
options={options}
onChange={onChannelXChange}
placeholder="Select an option"
/>
</div>
</td>
);
})}
</tr>
</tbody>
</table>
);
}
export default Table;
And it’s parent component:
import Table from "./Table";
import React, { useState } from "react";
class Workspace extends React.Component {
constructor(props) {
super();
this.state = {
workspaceState: {},
};
this.state.workspaceState = props.workspaceState;
this.handleCallback = this.handleCallback.bind(this);
}
handleCallback = (option) => {
this.props.workspaceState.value = option.value;
// I expect this to re-render the Table Component with the updated props
console.log("2. updating state");
this.setState({ workspaceState: this.props.workspaceState });
};
render() {
return (
<Table
enrichedEvents={this.props.enrichedEvents}
workspaceState={this.props.workspaceState}
className="workspace"
parentCallback={this.handleCallback}
></Table>
);
}
}
export default Workspace;
When the suer clicks on the Dropdown, I pass the value back up to the parent component (Workspace). This then updates the Workspace state, and I then expect the child coponent to be re-rendered – except it is not. When I look at the logs, I see:
Workspace.js:44 1. send the change back to the parent
Workspace.js:44 2. updating parent state component
Table.js:95 >> props is {workspaceState: { }}
But I dont see:
>> in useEffect
I only see this log the first time the app runs. The Table component is indeed getting the new updated props, but it wont re-render with this new data. What am I doing wrong?
Advertisement
Answer
useEffect(() => {}, []) replace the componentDidMount in old react versions that means it execute only once after mounting the component in DOM. I am wondering if you really need a useEffect in your case , if it the case you need to use a useEffect without array of dependencies. LIke that:
import { useEffect } from "react";
function Table(props) {
console.log(">> In Table, props is ", props);
useEffect(() => {
console.log(">> in useEffect ");
// prepare the data to render here
});
const options = [
{ value: 0, label: "1" },
{ value: 1, label: "2" }
];
const onChannelXChange = (option) => {
console.log("1. send the change back to the parent");
props.parentCallback(option);
};
return (
<Dropdown
options={options}
onChange={onChannelXChange}
placeholder="Select an option"
/>
);
}
export default Table;
Solution 2: As i said am wondering if you really need a useEffect you can directly do it like that
import { useEffect } from "react";
function Table(props) {
console.log(">> In Table, props is ", props);
// put you logic directly here
// prepare the data to render here
const options = [
{ value: 0, label: "1" },
{ value: 1, label: "2" }
];
const onChannelXChange = (option) => {
console.log("1. send the change back to the parent");
props.parentCallback(option);
};
return (
<Dropdown
options={options}
onChange={onChannelXChange}
placeholder="Select an option"
/>
);
}
export default Table;