I have a pretty specific case where my react component renders only a part of what is returned by the code.
General Idea:
I have a multidimentsional array:
Rows and Columns [][] of a not specified size, starting with 1 predefined element.
Each column contains one object of another set of components, which is supposed to be drawn conditionally / differently based on the type of the component.
To be able to read the code more easily i have splitted the array.map()
calls into seperate functions.
At the end in the return
of my component function (using a functional component here) I am only calling one function which does recursively generate JSX code to be filled in at once.
I did find this question which seems to be really similar to what i want to do.
In my code I am basically doing the same things, however React does not seem to render the Elements correctly.
The Issue:
React gets multiple elements back from React.CreateElement()
each at a time.
In the end the code is supposed to have a nested render of the multiple elements.
But only the first one Row
is rendered and appears in the DOM correctly.
The corresponding Column
which is supposed to be nested, does not appear in the DOM at all.
From further testing i can say that the components Functions Column
and the following element is never executed.
The JS-Object which is returned from JSX and CreateElement is correct though:
It contains the Children in its properties as it should. Its just never executed and thus never added.
What I tried:
I tried multiple ways.
I started with
const mapRows = () => {
return testvar.map((row, rowIndex) => {
return <Row key={"Row" + rowIndex}>{mapColumns(row, rowIndex)}</Row>;
});
};
// mapColumns
const mapColumns = (row, rowIndex) => {
return row.map((column, columnIndex) => {
return (
<Column key={"Column" + columnIndex}>
<DisplayedElement />
</Column>
);
});
};
went over a direct React.CreateElement
approach,
to now:
const mapRows = () => {
return testvar.map((row, rowIndex) => {
return <Row key={"Row" + rowIndex} children={mapColumns(row, rowIndex)}/>;
});
};
const mapCol = () => {
return (<Stuff/>)
}
In the end Neither of them worked.
The Example of the issue can be found here:
Sandbox Example Link
Just a quick reminder, i am not a professional coder at this point, so my code may seem in a weird style or may contain unnecessary elements.
Anyway,
Thanks!
Edit1 15.07. : Changed JSFiddle to Code Sandbox to show the issue. And Clarified example Code blocks to be more telling
What you need here is the predefined prop called children
.
When you wrap your elements as below,
<Row key={"Row" + rowIndex}>{mapColumns(row, rowIndex)}</Row>
then your Row
component gets a prop with all the child elements in a prop called children
. Use it to render them like below.
const Row = ({ children }) => {
return (
<div className="row" style={{ display: "flex", flexDirection: "row" }}>
{children}
</div>
);
};
Do the same for Column
.
Working Demo
const WorkingArea = () => {
// this is the same as in my project
let testvar = [
[{ elementtype: "element A" }, { elementtype: "element B" }],
[{ elementtype: "element C" }, { elementtype: "element D" }]
];
const mapRows = () => {
return testvar.map((row, rowIndex) => {
return <Row key={"Row" + rowIndex}>{mapColumns(row, rowIndex)}</Row>;
});
};
// mapColumns
const mapColumns = (row, rowIndex) => {
return row.map((column, columnIndex) => {
return (
<Column key={"Column" + columnIndex}>
<DisplayedElement type={column.elementtype} />
</Column>
);
});
};
return (
<div className="builder px-2">
<h3>Formular</h3>
<form className="mainForm">
<div className="dropArea border rounded p-3">{mapRows()}</div>
<button
type="submit"
className="btn btn-primary mt-1"
onClick={(e) => {
e.preventDefault();
}}
>
Submit
</button>
</form>
</div>
);
};
// Other Smaller Components, now in the same file for easier fiddle.
const Row = ({ children }) => {
return (
<div className="row" style={{ display: "flex", flexDirection: "row" }}>
{children}
</div>
);
};
const Column = ({ children }) => {
// Contains a lot of other react-dnd functions, probably not necessary thus skipped
return (
<div className="col" style={{ padding: "10px" }}>
{children}
</div>
);
};
const DisplayedElement = ({ type }) => {
return <div>{type}</div>;
};
ReactDOM.render(<WorkingArea />, document.querySelector('.react'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div class='react'></div>