简体   繁体   中英

Maintaining a List of React Components then rendering into parent

I have a hypothetical question about maintaining an array of polymorphic React components. Is it possible/good React practice to maintain an array of components that are descendants of a common component, then render them in the container? For instance:

import * as React from 'react';

import GenericBlock from './GenericBlock';
import { BlockTypeA, BlockTypeB, BlockTypeC } from './MyBlocks';

export default class BlockHolder extends React.Component {
    blocks : GenericBlock[] = [ <BlockTypeA />, <BlockTypeB />, <BlockTypeC /> ];

    render() {
        return (
            <div id="workspace">
                {
                    this.blocks
                }
            </div>);
    };
};

GenericBlock.tsx

import * as React from 'react';

export default class GenericBlock extends React.Component {
    render() { return (<div></div>); }
}

MyBlocks.tsx:

import * as React from 'react';

import GenericBlock from './GenericBlock';

class BlockTypeA extends GenericBlock {
    render() { return (<div></div>); }
};

class BlockTypeB extends GenericBlock {
    render() { return (<div></div>); }
};

class BlockTypeC extends GenericBlock {
    render() { return (<div></div>); }
};

export { BlockTypeA, BlockTypeB, BlockTypeC };

The above code snippet yields the error: Objects are not valid as a React child , but I think it captures the spirit of what I am talking about. Is there a way to make the above scheme work?

I am sure that this question has already been asked and answered, but I can't seem to get the Google Search correct.

EDIT :

Added Sandbox link: https://codesandbox.io/s/wizardly-wilson-vb7nn

Now I am encountering a new error: Type 'Element' is missing the following properties from type 'GenericBlock': render, context, setState, forceUpdate, and 2 more.

EDIT 2 :

Typing the blocks array as JSX.Element removes the error and makes everything work, but that doesn't seem like very good practice as JSX.Element can be any element, whereas the point of typing it as GenericBlock is to ensure that all the elements are descendants of a specific component.

in react code, it works perfectly: https://codesandbox.io/s/optimistic-ptolemy-g25ge

no errors, no warnings

import * as React from "react";

import { BlockTypeA, BlockTypeB, BlockTypeC } from "./MyBlocks";

export default class BlockHolder extends React.Component {
  blocks = [
    <BlockTypeA key={1} />,
    <BlockTypeB key={2} />,
    <BlockTypeC key={3} />
  ];

  render() {
    return <div id="workspace">{this.blocks}</div>;
  }
}

import * as React from "react";

export default class GenericBlock extends React.Component {
  render() {
    return <div />;
  }
}

import * as React from 'react';

import GenericBlock from './GenericBlock';

class BlockTypeA extends GenericBlock {
    render() { return (<div>A</div>); }
};

class BlockTypeB extends GenericBlock {
    render() { return (<div>B</div>); }
};

class BlockTypeC extends GenericBlock {
    render() { return (<div>C</div>); }
};

export { BlockTypeA, BlockTypeB, BlockTypeC };
"dependencies": {
    "react": "16.12.0",
    "react-dom": "16.12.0",
    "react-scripts": "3.0.1"
  },
  "devDependencies": {
    "typescript": "3.8.3"
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM