如何解决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)。然后它从这些“元素”中的每一个构建层并将它们传递回 DeckGL
的 layers
属性。
它们看起来像 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 举报,一经查实,本站将立刻删除。