React & Deck.GL:为每个 child 组件添加默认道具
React & Deck.GL: Add default props to each child component
我正在使用 Deck.GL 和 React 开发一组可配置的地图层。我有一个 BaseMap
组件,我会将数据层传递给它作为反应 children.
目前,我有这个:
底图:
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, 0]}
getText={getTextFn}
/>
</BaseMap>
没关系,但我想为每个 child 添加默认道具。
尝试 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 有关。
解决方案?
我可以想象两种解决方案(显然,可能还有其他解决方案!):
- 检查层类型和根据类型修改 child 道具的正确方法,或类似的东西 - 这可能吗?
或
- 一些方法可以说服 react/deck.gl
ScatterplotLayer
将是 Deck.GL
的 child,即使它不在 ScatterplotLayerWrapper
中。 (这个好像不太可能)
混淆来自对 deck.gl
的 React 组件如何工作以及那些 <ScatterplotLayer>
组件到底是什么(它们不是反应组件)的误解。
Deck.gl 的反应组件,DeckGL
,拦截所有子项并确定它们是否实际上是“伪装成反应元素的层”(参见 code)。然后它从每个“元素”构建层并将它们传递回 DeckGL
的 layers
属性.
它们看起来像 React 组件,但实际上不是。它们不能在 React 上下文中自行呈现。它们根本无法在 DeckGL
组件之外呈现,因为它们仍然只是普通的 deck.gl 层。
这里的解决方案是创建一个新的地图层 class 就像您在任何其他上下文中所做的那样(不是包裹层的 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 的子级, 或 :
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>
);
};
我正在使用 Deck.GL 和 React 开发一组可配置的地图层。我有一个 BaseMap
组件,我会将数据层传递给它作为反应 children.
目前,我有这个:
底图:
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, 0]}
getText={getTextFn}
/>
</BaseMap>
没关系,但我想为每个 child 添加默认道具。
尝试 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 有关。
解决方案?
我可以想象两种解决方案(显然,可能还有其他解决方案!):
- 检查层类型和根据类型修改 child 道具的正确方法,或类似的东西 - 这可能吗?
或
- 一些方法可以说服 react/deck.gl
ScatterplotLayer
将是Deck.GL
的 child,即使它不在ScatterplotLayerWrapper
中。 (这个好像不太可能)
混淆来自对 deck.gl
的 React 组件如何工作以及那些 <ScatterplotLayer>
组件到底是什么(它们不是反应组件)的误解。
Deck.gl 的反应组件,DeckGL
,拦截所有子项并确定它们是否实际上是“伪装成反应元素的层”(参见 code)。然后它从每个“元素”构建层并将它们传递回 DeckGL
的 layers
属性.
它们看起来像 React 组件,但实际上不是。它们不能在 React 上下文中自行呈现。它们根本无法在 DeckGL
组件之外呈现,因为它们仍然只是普通的 deck.gl 层。
这里的解决方案是创建一个新的地图层 class 就像您在任何其他上下文中所做的那样(不是包裹层的 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 的子级, 或 :
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>
);
};