react-leaflet如何动态改变矩形颜色?

时间:2019-01-29 02:22:55

标签: javascript reactjs leaflet react-leaflet

渲染Map之后,我创建了对API的一系列调用,并根据结果构造了Rectangles。然后,我根据用户希望看到的比例来更改Rectangle的颜色。使用香草js,这很容易,因为我只保留了所有Rectangles的引用并更新了color属性。但是使用react-leaflet时,我看不到做相同事情的方法。

HTML(此处为Leaflet CSS)

<!doctype html>
<html lang="en">

  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Leaflet CSS -->
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.4/dist/leaflet.css" integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA==" crossorigin="" />

    <!-- Bootstrap CSS-->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
    <!-- Fullscreen plugin CSS-->
    <link href='https://api.mapbox.com/mapbox.js/plugins/leaflet-fullscreen/v1.0.1/leaflet.fullscreen.css' rel='stylesheet' crossorigin="anonymous" />
  </head>
  <body>

  <div id='app'></div>

  <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
 </body>

</html>

Index.js

import React from 'react';
import ReactDom from 'react-dom';
import App from './components/App';

const appContainer = document.getElementById('app');

ReactDom.render(<App />, appContainer);

App.js(对于本演示来说是不必要的,但稍后会添加更多内容)

import React from 'react';
import MapController from './MapController';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: '',
    };
  }

 render() {
    return (
      <MapController />
    );
  }
}

export default App;

MapController.js-用于添加功能的Map组件的包装器

import React from 'react';
import {
  Map, ImageOverlay,
} from 'react-leaflet';
import { CRS } from 'leaflet';
import '../lib/leaflet-fullscreen';

  componentDidMount() {
    //After the map renders, start calling the API to create triangles
    this.createColorCodedPriceOverlays();
  }


  async createColorCodedPriceOverlays() {
      const pageSize = 100;
      let startingIndex = 0;
      const apiCalls = [];

      // Need to get the first batch to determine how many listings exist
      // getListings will update the Map on state and return a promise that
      // resolves to the total number of records that exist
      const total = await this.getListings(startingIndex);

      // Create the calls needed to get all parcels for sale
      while (startingIndex <= total) {
      startingIndex += pageSize;
      apiCalls.push(this.getListings(startingIndex));
 }

      Promise.all(apiCalls);
  }

  //Call api and create batch of Rectangles from the results
  async getListings(startingIndex) {
    const response = await fetch('www.foobarApi.io/batchx');
    const json = await response.json();
    const { parcels, total } = json.data;
    let price = (parcels[0] && parcels[0].publication) ?parcels[0].publication.price : undefined;
    const parcelRectangles = [];
    let rect;
    let i = 0;

    parcels.forEach((parcel) => {
    price = parcel.publication.price;

    //Create the <Rectangle
    //Simplified, usually dynamically set color
    rect = (<Rectangle bounds={[[0,0],[100,100]]} color="white" />)


    parcelRectangles.push(rect);
    i += 1;
  });

//Set the generated Rectangles on the State so I can get them later
this.setState((prevState) => {
  const allParcels = prevState.parcels ? [...prevState.parcels, ...parcelRectangles] : parcelRectangles;
  const totalParcelsRetrieved = prevState.totalParcelsRetrieved + parcelRectangles.length;

  return { parcels: allParcels, totalParcelsRetrieved };
});

return total;
  }

onValueChange(event) {
/ **
*  So now the user changed some values and I want to alter
* the color property of the <Rectangles> I have stored in
* the state. But I don't have anyway of doing this.
*/
}

render() {
    return (
        <div className="container-fluid">
            <div className="row map-row">
               <Map
                 center={[0, 0]}
                 zoom={3}
                 crs={L.CRS.Simple}
                 minZoom={1}
                 maxZoom={10}
                 bounds={[[-150.5, -150.5], [150.5, 150.5]]}
                 maxBounds={[[-150.5, -150.5], [150.5, 150.5]]}
                 maxBoundsViscosity={2.0}
                 fullscreenControl
                 attributionControl={false}
                 style={{ height: '100%', width: '100%' }}
            >
           //Stored Rectangles on the state to try and update them later
              {this.state.parcels}
              </Map>
              <UserControlsComponent onValueChange={this.onValueChange.bind(this)}/>
            </div>
        </div>
    );
}

2 个答案:

答案 0 :(得分:1)

我会建议通过状态管理矩形属性,而不是保留对矩形实例的引用。假设矩形数组的初始数据以以下格式表示:

[
    {
      name: "Rectangle 1",
      color: "white",
      bounds: [[10., 0.0], [20.0, 15.0]]
    },
    //...
]

和以下组件用于呈现矩形列表:

const RectangleList = ({ data }) => {
  return (
    <span>
      {data.map((item, i) => {
        return <Rectangle key={i} bounds={item.bounds} color={item.color} />;
      })}
    </span>
  );
}

然后下面的示例演示如何在外部事件上修改矩形颜色:

class MapExample extends Component {
  constructor(props) {
    super(props);
    this.state = {
      items: items
    };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(){
    const items = [...this.state.items];
    items[0].color = "red";
    this.setState({ items: items });
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>Change color</button>
        <Map center={this.props.center} zoom={this.props.zoom}>
          <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
          <RectangleList data={items} />
        </Map>
      </div>
    );
  }
}

Here is a demo供参考

答案 1 :(得分:0)

我没有保留Rectangle中的this.state.parcels组件并试图直接对其进行更新,而是必须保留每个Rectangle的参数,并在更改调用this.state.setState({rectangelProps})的参数时使用新属性呈现每个Rectangle。我没有意识到setState每次都叫render