如何处理“多态”功能组件

时间:2019-11-21 21:55:01

标签: javascript reactjs typescript

想象一下我正在编写一个React应用,用户可以在其中向不同的“工作区”添加不同颜色和尺寸的形状。假设我们有CircleSquare组件,它们将具有不同的属性来定义它们。当用户添加形状时,其道具将添加到工作区组件的状态。然后,工作区将绘制如下形状:

import React, {useState} from "react";

interface ISquareProps {
    color: string;
    lineLength: number;
}

interface ICircleProps {
    color: string;
    radius: number;
}

const Square = ({lineLength}: ISquareProps) => (<div>I'm a square with line length {lineLength}</div>);
const Circle = ({radius}: ICircleProps) => (<div>I'm a circle with radius {radius}</div>);

const Workspace = () => {
    const [squares, setSquares] = useState(new Array<ISquareProps>());
    const [circles, setCircles] = useState(new Array<ICircleProps>());

    return (
        <>
            {squares.map((square) => <Square {...square} /> )}
            {circles.map((circle) => <Circle {...circle} /> )}
        </>
    );
};

在此处查找示例:

Edit draw-shapes-1

虽然这对于两种不同的形状都适用,但如果我们有很多形状,就会变得很麻烦。

如果形状知道如何渲染自己该怎么办?那呢:

import React, {useState} from "react";

interface IShapeProps {
    color: string;
    render(): JSX.Element;
}

// ------- square -------
interface ISquareProps extends IShapeProps {
    lineLength: number;
}

const Square = ({lineLength}: ISquareProps) => (<div>I'm a square with line length {lineLength}</div>);

class SquareProps implements ISquareProps {
    public color: string;
    public lineLength: number;

    constructor(lineLength: number, color: string) {
        this.color = color;
        this.lineLength = lineLength;
    }

    public render() {
        return <Square {...this} />;
    }
}
// ------- circle -------
interface ICircleProps extends IShapeProps {
    radius: number;
}

const Circle = ({radius}: ICircleProps) => (<div>I'm a circle with radius {radius}</div>);

class CircleProps implements ICircleProps {
    public color: string;
    public radius: number;

    constructor(color: string, radius: number) {
        this.color = color;
        this.radius = radius;
    }

    public render() {
        return <Circle {...this} />;
    }
}
// ------- workspace -------
const Workspace = () => {
    const [shapes, setShapes] = useState(new Array<IShapeProps>());

    return (
        <>
            {shapes.map((shape) => shape.render() )}
        </>
    );
};

一个工作示例在这里:

Edit draw-shapes-2

这是处理带有功能组件的“多态”组件的可行方法吗? 是否应该考虑替代模式?

1 个答案:

答案 0 :(得分:0)

您似乎正在做的只是使用ShapeCircle组件,但是据我所知,您的render方法实际上并不能告诉形状是什么形状。 您需要对该渲染函数进行参数设置,以决定它是哪个。

您可以进行一些改进:

1)虽然对我来说更有意义,而不是仅仅使用一些“功能”来简化它,而是将其包装在足够明智的react组件中。

2)使用道具代替类属性,这就是它们的目的。没有理由将其重新分配给this变量

3)使用条件JSX根据道具决定要渲染的组件(您甚至可以切换形状,并且它们会随着新道具触发重新渲染而切换)

4)我认为不需要单独实现您拥有的prop接口,可以与功能组件内联实现


export const Shape = (props: IShapeProps) => {

    public render() {
        if (this.props.shapeType === 'Square') {
           return <Square lineheight={this.props.lineheight} color={this.props.color} />;
        } else {
           return <Circle radius={this.props.radius} color={this.props.color} />;
        }  
    }
}