微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

React & Deck.GL:为每个子组件添加默认道具

如何解决React & Deck.GL:为每个子组件添加默认道具

我正在使用 Deck.GL 和 React 处理一组可配置的地图层。我有一个 BaseMap 组件,我会将数据层作为 react 子项传递给它。

目前,我有这个:

底图:

export const BaseMap = ({ latitude = 0,longitude = 0,zoom = 4,children }) => {
    const deckProps = {
        initialViewState: { latitude,longitude,zoom },controller: true
    };
    return (
        <DeckGL {...deckProps}>
            {children}
            <StaticMap />
        </DeckGL>
    );
};

它是这样使用的:

<BaseMap>
    <ScatterplotLayer
        data={scatterData}
        getPosition={getPositionFn}
        geTradius={1}
        radiusUnits={'pixels'}
        radiusMinPixels={1}
        radiusMaxPixels={100}
        filled={true}
        getFillColor={[255,255,255]}
    />
    <TextLayer
        data={textData}
        getPosition={getPositionFn}
        getColor={[255,0]}
        getText={getTextFn}
    />
</BaseMap>

这没关系,但我想为每个孩子添加认道具。

尝试 1

我已在 BaseMap 中尝试过此操作,但收到错误 cannot assign to read only property props of object #<Object>

...
return (
    <DeckGL {...deckProps}>
        {React.Children.map(children,(c) => {
            const defaultProps = {
                loaders: [CSVLoader]
            }
            c.props = { ...defaultProps,...c.props };
            return c;
        })}
    </DeckGL>
);

尝试 2

我还尝试为每种类型的层创建包装器组件,但收到错误 Cannot call a class as a function

包装器:

export const ScatterplotLayerWrapper = (props) => {
    const defaultScatterProps = {
        loaders: [CSVLoader]
    };
    const scatterLayerProps = {
        ...defaultScatterProps,...props
    };
    return <ScatterplotLayer {...scatterLayerProps} />;
};

这样使用:

<BaseMap>
    <ScatterplotLayerWrapper
        data={scatterData}
        getPosition={getPositionFn}
    />
</BaseMap>

我怀疑第二次尝试的问题与 caveat here 有关。

解决方案?

我可以想象两种类型的解决方案(显然,可能还有其他解决方案!):

  • 检查图层类型和根据类型修改子道具的正确方法,或类似的东西 - 这可能吗?

  • 某种方式来说服 react/deck.gl ScatterplotLayer 将是 Deck.GL 的孩子,即使它不在 ScatterplotLayerWrapper 中。 (这个似乎不太可能)

解决方法

混淆源于对 deck.gl 的 React 组件的工作原理以及那些 <ScatterplotLayer> 组件的真正含义(它们不是 React 组件)的误解。

Deck.gl 的 react 组件 DeckGL 拦截所有子元素并确定它们是否实际上是“伪装成 react 元素的层”(参见 code)。然后它从这些“元素”中的每一个构建层并将它们传递回 DeckGLlayers 属性。

它们看起来像 React 组件,但实际上不是。它们不能在 React 上下文中单独呈现。它们根本无法在 DeckGL 组件之外呈现,因为它们仍然只是普通的 Deck.gl 层。

这里的解决方案是创建一个新的地图图层类,就像您在任何其他上下文中所做的一样(不是一个包裹图层的 React 组件)。相关文档为 here

class WrappedTextLayer extends CompositeLayer {
    renderLayers() { // a method of `Layer` classes
        // special logic here
        return [new TextLayer(this.props)];
    }
}
WrappedTextLayer.layerName = 'WrappedTextLayer';
WrappedTextLayer.defaultProps = {
    getText: (): string => 'x',getSize: (): number => 32,getColor: [255,255,255]
};

export { WrappedTextLayer };

然后可以在 BaseMap 组件(或未包装的 DeckGL 组件`)中使用这个新层,如下所示:

<BaseMap>
    <WrappedTextLayer
        data={dataUrl}
        getPosition={(d) => [d.longitude,d.latitude]}
    />
</BaseMap>

此外,完全相同的图层可以作为图层道具传递给DeckGL

<DeckGL
    layers={[
        new WrappedTextLayer({
            data: dataUrl,getPosition: (d) => [d.longitude,d.latitude]
        })
    ]}
></DeckGL>

稍微修改 BaseMap 组件将允许它通过 layers 属性接受层作为 JSX-like 子层,

export const BaseMap = ({ latitude = 0,longitude = 0,zoom = 4,children,layers }) => {
    const deckProps = {
        initialViewState: { latitude,longitude,zoom },controller: true,layers
    };
    return (
        <DeckGL {...deckProps}>
            {children && !layers ? children : null}
            <StaticMap />
        </DeckGL>
    );
};

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。