I have a tree like JSON structure and it can be n
levels deep. Here is an example:
"plot": {
"population": "All",
"gates": [
{
"name": "population1",
"plot": {
"population": "population1",
"gates": [
{
"name": "population3",
"plot": {
"population": "population3",
}
}
]
}
},
{
"name": "population2",
"plot": {
"population": "population4",
}
}
]
};
It starts with plot
. The is the top level. A plot can have many gates
. These are essentially branches. Each gate
has another plot
, which can have multiple gates
etc.
I want to output the plot.population
within JSX wrapped in a div
. Here is my attempt (MultiStainState
is a JSON file with the above JSON):
function Plot(props) {
...
const renderPlots = (plotObject) => {
console.log("plotObject is ", plotObject);
if (plotObject) {
return (
<>
<div>{plotObject.population}</div>
</>
);
}
{
plotObject.gates.map((gate, gateIndex) => {
plotObject(gate.plot);
});
}
};
return (
<div
style={{
height: "200px",
}}
>
Render Plots:
{renderPlots(MultiStainState)}
</div>
);
}
This output Render Plots:All
and none of the child plot populations.
This is presumably because of the return
within renderPlots()
. I feel like I need to use recursion here (as I have attempted to do). But I cant figure out how....
CodePudding user response:
Here is a simple rendering of a recursive component based on this article. It checks if it has a gates array of length > 0 and if so will recursively render the component
sandbox
const plot = {
"population": "All",
"gates": [
{
"name": "population1",
"plot": {
"population": "population1",
"gates": [
{
"name": "population3",
"plot": {
"population": "population3",
}
}
]
}
},
{
"name": "population2",
"plot": {
"population": "population4",
}
}
]
}
const RecursiveComponent = ({ population, gates }) => {
const hasGates = gates && gates.length
return (
<React.Fragment>
<div>
{population}
</div>
{hasGates && gates.map(({name,plot}) => <RecursiveComponent key={name} population={plot.population} gates={plot.gates} />)}
</React.Fragment>
);
};
const App = props => {
return (
<RecursiveComponent population={plot.population} gates={plot.gates} /> //starting point
);
};
ReactDOM.render(<App />, document.getElementById("app"));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="app"></div>
CodePudding user response:
The main issue with your renderPlots
function is that if the given plotObject
is non-null, the function just returns plotObject.population
and never gets to the recursive step. There are some other issues with that function, but I'm going to offer a rewrite that will address those.
I'm not sure of your exact desired output format, but I'm going to use nesting <div>
elements so that the DOM hierarchy matches the JSON structure.
You'll want to return a single JSX object with the recursive step within (recursion looks a bit weird in React/JSX compared to usual programming). I've also split the renderPlots
function into a separate component, but that's more of a stylistic choice (I'll leave you to find a better name for the component).
Here's a simple example:
function PlotRender({ plotObject }) {
if (!plotObject) {
return null; // just in case
}
return (
<div>
{plotObject.population}
{plotObject.gates?.map(e => (
<PlotRender key={e.name} plotObject={e.plot}/>
))}
</div>
);
}
Which will render as (for the given sample data):
<div>
All
<div>
population1
<div>
population3
</div>
</div>
<div>
population4
</div>
</div>
Note also that in the outer <Plot>
component, you'll likely need to pass MultiStainState.plot
as the plotObject
prop to <PlotRender>
rather than just MultiStainState
.