高阶组件:默认道具
Higher Order Component: Default Props
我有这段代码并试图用反应包装一个 HOC Class。我首先想要的是覆盖默认参数的一部分。所以这是我的代码(你不需要阅读整个代码,问题只是关于 HOC 中的 defaultProps)
首先是组件:
import React from 'react';
// recompose
import compose from 'recompose/compose';
import defaultProps from 'recompose/defaultProps';
import withState from 'recompose/withState';
import withHandlers from 'recompose/withHandlers';
import withProps from 'recompose/withProps';
// utils
import { themr } from 'react-css-themr';
import { suslovkaCoords, generateMarkers } from './utils/fakeData';
// controls
import CanvasHoverMap from './controls/Map';
import HoveredTooltipMarker from './controls/Markers/HoveredTooltipMarker';
import TooltipMarker from './controls/Markers/TooltipMarker';
// components
import RoomTooltip from '../RoomTooltip/RoomTooltip';
// styles
import styles from './map.sass';
import mapStyles from './controls/Map/mapSytles';
const MARKERS_COUNT = 3000;
export const map = ({
theme,
style,
options,
markerHoverDistance,
markers,
renderMarkers,
renderMarker,
mapParams: {
zoom,
center,
},
setMapParams,
onMapParamsChange,
selectedMarker,
setSelectedMarker,
isMobile,
refresh,
}) => (
<div className={theme.component}>
<CanvasHoverMap
// flex: 1 here
style={style}
// google map options https://developers.google.com/maps/documentation/javascript/controls#ControlOptions
options={options}
// see CanvasMap onMouseMove, distance at which algorithm decides that marker is hovered
markerHoverDistance={markerHoverDistance}
// google-map-react props
center={center}
zoom={zoom}
onChange={onMapParamsChange}
// canvas markers, and render functions
markers={markers}
// render markers at canvas
renderMarkers={renderMarkers}
// render hovered marker as is
renderMarker={renderMarker}
// to force redraw just pass a new empty object to refresh for example
refresh={refresh}
// selected marker always visible over canvas (+ tooltip)
selectedMarker={selectedMarker}
setSelectedMarker={setSelectedMarker}
// mobile-detect
isMobile={isMobile}
setMapParams={setMapParams}
/>
</div>
);
现在是 HOC:
export const mapHOC = compose(
themr('map', styles),
defaultProps({
options: {
scrollwheel: true,
zoomControl: true,
zoomControlOptions: {
position: 1, // google.maps.ControlPosition.LEFT_TOP
},
minZoom: 3,
zoom: 10,
maxZoom: 18,
// disableDoubleClickZoom: true,
styles: mapStyles,
},
style: {
flex: 1,
},
hoverDistance: 15,
markerHoverDistance: 15,
markers: generateMarkers(MARKERS_COUNT, 0.0003),
}),
withState('mapParams', 'setMapParams', { center: suslovkaCoords, zoom: 8 }),
withState('selectedMarker', 'setSelectedMarker', null),
withProps(({ selectedMarker }) => ({
isSelected: (marker) => selectedMarker
? selectedMarker.id === marker.id
: false,
})),
withHandlers({
onMapParamsChange: ({ setMapParams }) => ({ center, zoom, bounds }) => {
setMapParams({ center, zoom, bounds });
console.log('setMapParams', { center, zoom });
},
renderMarker: ({ theme, setSelectedMarker, isSelected, isMobile }) => (marker) => {
const tooltipMarkerProps = {
key: marker.id,
theme: {theme},
themeNamespace: 'tooltipMarker',
initialScale: 1,
defaultScale: 1,
hoveredScale: 1.3,
tooltipContent: <RoomTooltip marker={marker} />,
paddingOffset: 10, // used for tooltip position
tooltipContentHeight: 240, // no need to be exact, used for tooltip position
tooltipContentWidth: 200, // no need to be exact, used for tooltip position
setSelectedMarker: setSelectedMarker,
selected: isSelected(marker),
marker: marker,
...marker,
};
return isMobile
? <TooltipMarker {...tooltipMarkerProps } />
: <HoveredTooltipMarker {...tooltipMarkerProps} />;
},
// be sure in current implementation markers is tile markers, not all markers.
// tiling is used as it allows some perf optimizations not used here
renderMarkers: () => ({ ctx, markers, tileSize }) => {
ctx.clearRect(0, 0, tileSize, tileSize);
const radius = 5;
markers.forEach(({ /* id, */ x, y }) => {
// just circles here but can be images, use id or other marker props to render
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
ctx.beginPath();
ctx.arc(x, y, radius + 3, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
ctx.fillStyle = 'white';
ctx.beginPath();
ctx.arc(x, y, radius + 2, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
ctx.fillStyle = '#00b92a';
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
});
},
}),
);
我想从 defaultProps 中删除 "markers: generateMarkers(MARKERS_COUNT, 0.0003)" 并从外部给出标记。
到目前为止我尝试了什么:
const newmap = mapHOC(map);
class MapWithState extends React.Component {
constructor(props) {
super(props);
}
render() {
const markers = generateMarkers(MARKERS_COUNT, 0.0003);
return (<newmap markers={markers} />);
}
}
export default MapWithState;
//export default mapHOC(map);
知道如何做这样的事情吗?我希望它可以毫不费力地完成。谢谢!
React 在创建组件时合并 Props。
意味着,当一个组件 (JSX) 被实例化时,它会创建一个 public 数据和私有数据,即分别为状态和道具。
在为组件创建道具时,它会获取所有参数道具(来自被调用者),并且还会考虑是否在它可以填充的 class 中声明了任何默认道具。
类似于Object.assign({}, { ...defaultProps }, { ...userProps })
其中 defaultProps
将被 userProps
覆盖。如果 userProps
不可用,则考虑 defaultProps
。
因此,在您的情况下,您需要删除默认道具,<newmap markers={markers} />
这应该有效。
我有这段代码并试图用反应包装一个 HOC Class。我首先想要的是覆盖默认参数的一部分。所以这是我的代码(你不需要阅读整个代码,问题只是关于 HOC 中的 defaultProps)
首先是组件:
import React from 'react';
// recompose
import compose from 'recompose/compose';
import defaultProps from 'recompose/defaultProps';
import withState from 'recompose/withState';
import withHandlers from 'recompose/withHandlers';
import withProps from 'recompose/withProps';
// utils
import { themr } from 'react-css-themr';
import { suslovkaCoords, generateMarkers } from './utils/fakeData';
// controls
import CanvasHoverMap from './controls/Map';
import HoveredTooltipMarker from './controls/Markers/HoveredTooltipMarker';
import TooltipMarker from './controls/Markers/TooltipMarker';
// components
import RoomTooltip from '../RoomTooltip/RoomTooltip';
// styles
import styles from './map.sass';
import mapStyles from './controls/Map/mapSytles';
const MARKERS_COUNT = 3000;
export const map = ({
theme,
style,
options,
markerHoverDistance,
markers,
renderMarkers,
renderMarker,
mapParams: {
zoom,
center,
},
setMapParams,
onMapParamsChange,
selectedMarker,
setSelectedMarker,
isMobile,
refresh,
}) => (
<div className={theme.component}>
<CanvasHoverMap
// flex: 1 here
style={style}
// google map options https://developers.google.com/maps/documentation/javascript/controls#ControlOptions
options={options}
// see CanvasMap onMouseMove, distance at which algorithm decides that marker is hovered
markerHoverDistance={markerHoverDistance}
// google-map-react props
center={center}
zoom={zoom}
onChange={onMapParamsChange}
// canvas markers, and render functions
markers={markers}
// render markers at canvas
renderMarkers={renderMarkers}
// render hovered marker as is
renderMarker={renderMarker}
// to force redraw just pass a new empty object to refresh for example
refresh={refresh}
// selected marker always visible over canvas (+ tooltip)
selectedMarker={selectedMarker}
setSelectedMarker={setSelectedMarker}
// mobile-detect
isMobile={isMobile}
setMapParams={setMapParams}
/>
</div>
);
现在是 HOC:
export const mapHOC = compose(
themr('map', styles),
defaultProps({
options: {
scrollwheel: true,
zoomControl: true,
zoomControlOptions: {
position: 1, // google.maps.ControlPosition.LEFT_TOP
},
minZoom: 3,
zoom: 10,
maxZoom: 18,
// disableDoubleClickZoom: true,
styles: mapStyles,
},
style: {
flex: 1,
},
hoverDistance: 15,
markerHoverDistance: 15,
markers: generateMarkers(MARKERS_COUNT, 0.0003),
}),
withState('mapParams', 'setMapParams', { center: suslovkaCoords, zoom: 8 }),
withState('selectedMarker', 'setSelectedMarker', null),
withProps(({ selectedMarker }) => ({
isSelected: (marker) => selectedMarker
? selectedMarker.id === marker.id
: false,
})),
withHandlers({
onMapParamsChange: ({ setMapParams }) => ({ center, zoom, bounds }) => {
setMapParams({ center, zoom, bounds });
console.log('setMapParams', { center, zoom });
},
renderMarker: ({ theme, setSelectedMarker, isSelected, isMobile }) => (marker) => {
const tooltipMarkerProps = {
key: marker.id,
theme: {theme},
themeNamespace: 'tooltipMarker',
initialScale: 1,
defaultScale: 1,
hoveredScale: 1.3,
tooltipContent: <RoomTooltip marker={marker} />,
paddingOffset: 10, // used for tooltip position
tooltipContentHeight: 240, // no need to be exact, used for tooltip position
tooltipContentWidth: 200, // no need to be exact, used for tooltip position
setSelectedMarker: setSelectedMarker,
selected: isSelected(marker),
marker: marker,
...marker,
};
return isMobile
? <TooltipMarker {...tooltipMarkerProps } />
: <HoveredTooltipMarker {...tooltipMarkerProps} />;
},
// be sure in current implementation markers is tile markers, not all markers.
// tiling is used as it allows some perf optimizations not used here
renderMarkers: () => ({ ctx, markers, tileSize }) => {
ctx.clearRect(0, 0, tileSize, tileSize);
const radius = 5;
markers.forEach(({ /* id, */ x, y }) => {
// just circles here but can be images, use id or other marker props to render
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
ctx.beginPath();
ctx.arc(x, y, radius + 3, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
ctx.fillStyle = 'white';
ctx.beginPath();
ctx.arc(x, y, radius + 2, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
ctx.fillStyle = '#00b92a';
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
});
},
}),
);
我想从 defaultProps 中删除 "markers: generateMarkers(MARKERS_COUNT, 0.0003)" 并从外部给出标记。
到目前为止我尝试了什么:
const newmap = mapHOC(map);
class MapWithState extends React.Component {
constructor(props) {
super(props);
}
render() {
const markers = generateMarkers(MARKERS_COUNT, 0.0003);
return (<newmap markers={markers} />);
}
}
export default MapWithState;
//export default mapHOC(map);
知道如何做这样的事情吗?我希望它可以毫不费力地完成。谢谢!
React 在创建组件时合并 Props。
意味着,当一个组件 (JSX) 被实例化时,它会创建一个 public 数据和私有数据,即分别为状态和道具。
在为组件创建道具时,它会获取所有参数道具(来自被调用者),并且还会考虑是否在它可以填充的 class 中声明了任何默认道具。
类似于Object.assign({}, { ...defaultProps }, { ...userProps })
其中 defaultProps
将被 userProps
覆盖。如果 userProps
不可用,则考虑 defaultProps
。
因此,在您的情况下,您需要删除默认道具,<newmap markers={markers} />
这应该有效。