高阶组件:默认道具

时间:2017-10-22 12:23:54

标签: javascript reactjs higher-order-components recompose

我有这个代码,并尝试使用react类包装HOC。我想要的首先是覆盖默认参数的一部分。所以这是我的代码(你不需要阅读整个代码,这个问题只是关于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();
      });
    },
  }),
);

我想删除&#34;标记:generateMarkers(MARKERS_COUNT,0.0003)&#34;来自defaultProps并从外部提供标记。

到目前为止我尝试了什么:

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);

知道如何做这样的事吗?我希望它可以毫不费力地完成。谢谢!

1 个答案:

答案 0 :(得分:0)

React merge在创建组件时道具。

意思是,当一个组件(JSX)被实例化时,它会分别创建一个公共数据和私有数据,即state和props。

当为组件创建道具时,它会获取所有参数道具(来自被调用者)并且还会考虑是否在该类中声明了任何可以填写的默​​认道具。

Object.assign({}, { ...defaultProps }, { ...userProps })之类的东西 其中defaultProps将被userProps覆盖。如果无法使用userProps,则会考虑defaultProps

因此,在您的情况下,您需要删除默认道具,<newmap markers={markers} />这应该有用。