Wednesday, June 5, 2024
 Popular · Latest · Hot · Upcoming
128
rated 0 times [  129] [ 1]  / answers: 1 / hits: 18340  / 6 Years ago, mon, march 5, 2018, 12:00:00

I'm working on a component mapping function that loops through a list of objects which have a type key. The function returns an object of types of React components, it looks like this:



import _ from 'lodash';
import cellBodyTypes from './cellBodyTypes';
import {
GenericCellBody,
SubData
} from './components/CellBody';

const columnMapper = {};

_.forEach(cellBodyTypes, (type) => {
switch (type) {
case cellBodyTypes.SUB_DATA:
columnMapper[type] = SubData;
break;
case cellBodyTypes.DEFAULT:
columnMapper[type] = GenericCellBody;
break;
default:
columnMapper[type] = GenericCellBody;
}
});

export default columnMapper;


And it's used like this:



renderCellBody = (columnType, cellData, index) => {
const type = columnType || cellBodyTypes.DEFAULT;
const CellBodyComponent = columnMapper[type];

return <CellBodyComponent />;
}


And the render looks something like:



render (
<div>
{this.props.cellData.map((cell, index) => (
<div key={cell.id}>
{this.renderCellBody(cell.type, cell, index)}
</div>
))}
</div>
);


What I want to do is to be able to assign column types for new cases which utilize the same React components as other cases, but decorate those new column types with additional props. Something like:



case cellBodyTypes.NUMBER_SUB_DATA:
columnMapper[type] = React.cloneElement(SubData, {someAdditionalProp: 'something'});
break;
case cellBodyTypes.SINGLE_NUMBER:
columnMapper[type] = React.cloneElement(GenericCellBody, {someAdditionalProp: 'something'});
break;


I tried returning a clone of the React component using React.cloneElement but that does not work, as it gives me this error: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object.



Is there a way to do this? Am I close to the right path and just missing something? Thanks.


More From » reactjs

 Answers
1

That is because React.cloneElement return a react element, not component. So after



columnMapper[type] = React.cloneElement(SubData,...,



columnMapper[type] will containt an element.



But problem is that in renderCellBody function, you are trying to convert an element again into element by writing



return <CellBodyComponent />;


And that throws an error.



I would suggest that you keep columnMapper an array of elements. So the switch/case code should look something like this



_.forEach(cellBodyTypes, (type) => {
switch (type) {
case cellBodyTypes.SUB_DATA:
// Store element instead of component
columnMapper[type] = <SubData />;
break;
case cellBodyTypes.DEFAULT:
// Store element instead of component
columnMapper[type] = <GenericCellBody />;
break;
case cellBodyTypes.NUMBER_SUB_DATA:
columnMapper[type] = React.cloneElement(SubData, {someAdditionalProp: 'something'});
break;
case cellBodyTypes.SINGLE_NUMBER:
columnMapper[type] = React.cloneElement(GenericCellBody, {someAdditionalProp: 'something'});
break;
default:
columnMapper[type] = <GenericCellBody />;
}
});


So now columnMapper is an array of elements. Therefore in renderCellBody function, you don't need to convert them into element again. You can simply return the value



renderCellBody = (columnType, cellData, index) => {
const type = columnType || cellBodyTypes.DEFAULT;
const CellBodyComponent = columnMapper[type];

// CellBodyComponent is already an element. So directly return it.
return CellBodyComponent;
}

[#55008] Thursday, March 1, 2018, 6 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
luzv

Total Points: 178
Total Questions: 105
Total Answers: 114

Location: Palau
Member since Tue, May 30, 2023
1 Year ago
;