如何重做Reactjs犯罪地图应用程序

时间:2017-08-18 11:45:24

标签: javascript reactjs redux

我正在开发一个演示反应应用程序 - 重要的是将redux添加到此。请查看以下代码并帮助我适当地调用redux。

我想了解如何稍后将姐妹组件添加到此类应用程序以共享此通信通道 - 如果它在图表/组件之间创建主/从关系。

// index.js

import React from 'react'
// only load what you're actually using
import { Map, Marker, GoogleApiWrapper } from 'google-maps-react'
import './MapChart.css'

// this is a stateless component, it doesn't need state or event handlers
const MapContainer = ({ google, markers }) => (
  <Map 
    google={google} 
    initialCenter={{
      lat: 52.268,
      lng: 0.543
    }}
    zoom={9}
  >
    {
      markers.map((marker, i) =>
        // since you've mapped your data to just the props you need
        // you can just spread it into the component

        <Marker
            key={i}
            icon={marker.icon}
            title={marker.label}
            name={marker.name}
            position={{lat: marker.position.lat, lng: marker.position.lng}} />

      )
    }
  </Map>
)

export default GoogleApiWrapper({
  apiKey: 'xxxxx'
})(MapContainer)

// MapChart.js

 /* Always set the map height explicitly to define the size of the div
   * element that contains the map. */
  #map {
    height: 100%;
  }
  /* Optional: Makes the sample page fill the window. */
  html, body {
    height: 100%;
    margin: 0;
    padding: 0;
  }

// MapChart.css

import React, { Component } from 'react'
import { render } from 'react-dom'
import {Provider, connect} from 'react-redux'
import {createStore, applyMiddleware} from 'redux' 
import thunk from 'redux-thunk';

import MapChart from './modules/mapChart/MapChart'
import './index.css'

function fetchPostsRequest(){
  return {
    type: "FETCH_REQUEST"
  }
}

function fetchPostsSuccess(payload) {
  return {
    type: "FETCH_SUCCESS",
    payload
  }
}

function fetchPostsError() {
  return {
    type: "FETCH_ERROR"
  }
}

const reducer = (state = {}, action) => {
  switch (action.type) {
    case "FETCH_REQUEST":
      return state;
    case "FETCH_SUCCESS": 
      return {...state, posts: action.payload};
    default:
      return state;
  }
} 

function fetchPostsWithRedux() {
  return (dispatch) => {
    dispatch(fetchPostsRequest());
    return fetchPosts().then(([response, json]) =>{
      if(response.status === 200){
        dispatch(fetchPostsSuccess(json))
      }
      else{
        dispatch(fetchPostsError())
      }
    })
  }
}

function fetchPosts() {
  const URL = 'https://data.police.uk/api/crimes-street/all-crime?poly=52.268,0.543:52.794,0.238:52.130,0.478&date=2017-01';
  return fetch(URL, { method: 'GET'})
     .then( response => Promise.all([response, response.json()]));
}



// this is how you'll get your icon links
// instead of a switch with loads of repetitive bytes
const iconMap = {
  'anti-social-behaviour':  'green-dot',
  'burglary':               'red-dot',
  'criminal-damage-arson':  'yellow-dot',
  'drugs':                  'purple-dot',
  'other-theft':            'pink-dot',
  'shoplifting':            'blue-dot',
  'vehicle-crime':          'orange-dot',
  'other-crime':            'ltblue-dot'
}

// this is a class because it needs state
class CrimeMap extends Component {
  // to do this you have to make sure you have
  // the transform-class-properties feature in babel
  // otherwise just set your initial state in a constructor
  // constructor(props) {
  //   super(props)
  //   this.state = { markers: [] }
  // }
  state = {
    markers: []
  }

  componentDidMount() {
    console.log('prop ', this.props)
    // use fetch instead of jQuery
    // jQuery is a big lib to be loading for some fetching
    fetch(this.props.source)
      .then( response => response.json() )
      .then(
        json => this.setState({
          markers: this.mapLayerData(json)
        }),
        err => { 
          // handle errors 
        }
      )
  }

  // store only the data you want to pass as props to each Marker
  // instead of mapping it directly in MapChart every time it renders
  mapLayerData(markers) {
    // use a standard map function instead of $.each
    // destructuring saves time and repetition
    return markers.map(({ category, location }) => ({
      // use a template string and a simple map of icon names to get your icon uri
      icon: 'http://maps.google.com/mapfiles/ms/icons/'+ iconMap[category] +'.png',
      label: category,
      name: category,
      position: {
        lat: location.latitude,
        lng: location.longitude
      }
    }))
  }

  render() {
    // there's only one layer, so render it directly
    return (
      <div className="app">
        <MapChart markers={this.state.markers} />
      </div>
    )
  }
}



function mapStateToProps(state){
  return {
    posts: state.posts
  }
}


let Container = connect(mapStateToProps, {fetchPostsWithRedux})(CrimeMap);

const store = createStore(
    reducer,
    applyMiddleware(thunk)
);


//https://data.police.uk/docs/method/crime-street/
render(
    <Provider store={store}>
      <Container/>
    </Provider>,
    document.getElementById('root')
);

/////////////

这是我添加redux所得到的 - 但是我收到了错误

动作必须是普通对象。使用自定义中间件进行异步操作。我基于这个例子 - 但我不明白如何添加/定义这个thunk?它是什么?

http://jsfiddle.net/cdagli/b2uq8704/6/

index.js

{{1}}

1 个答案:

答案 0 :(得分:1)

以下是您共享的代码流程 1.当组件安装时,它会调用一个函数 2.此函数“fetchPostsWithRedux”然后调度动作,它向服务器发送api调用以获取数据 3.当收到数据时,组件重新渲染,更新数据为prop。

现在,如果你想使用mapLayerData函数将数据提供给组件,而不使用“旧的获取方法”,你可以按照下面的说明进行操作

添加一个函数命名componentWillReceiveProps

componentWillReceiveProps(nextProps){

    this.setState({markers: this.mapLayerData(nextProps.posts)});

}

一旦你调用它,组件的状态现在将拥有我们从api调用中收到的数据

希望上述解决方案能够明确一些。