Reactjs 在渲染部件外部调用函数

Reactjs 在渲染部件外部调用函数,reactjs,google-maps,react-apollo,Reactjs,Google Maps,React Apollo,我是React和Apollo(GraphQL)的新手。当用户点击谷歌地图标记时,我需要显示一个图层。我的阿波罗请求根据数据库中找到的任务正确显示标记,我面临的唯一问题是onClick返回TypeError:\u this.handleMissionClick不是函数。我认为这是因为函数在渲染部分和主类之外,无法找到链接这两个部分的方法 以下是完整的页面代码: // @flow import React from 'react' import { withScriptjs, withGoogleM

我是React和Apollo(GraphQL)的新手。当用户点击谷歌地图标记时,我需要显示一个图层。我的阿波罗请求根据数据库中找到的任务正确显示标记,我面临的唯一问题是onClick返回
TypeError:\u this.handleMissionClick不是函数
。我认为这是因为函数在渲染部分和主类之外,无法找到链接这两个部分的方法

以下是完整的页面代码:

// @flow
import React from 'react'
import { withScriptjs, withGoogleMap, GoogleMap, Marker } from "react-google-maps"
import gql from 'graphql-tag'
import { graphql } from 'react-apollo'
import { connect } from 'react-redux'
import Layer from 'grommet/components/Layer'
import MissionDetails from './../missions/details'

type TMission = {
  id : string,
  description: string,
  status: string,
  title: string,
  location: number[]
}

type TMissionProps = {
  data: {
    loading: boolean,
    searchMissions?: Array<TMission>
  }
}

function setIcon (status) {
  switch(status) {
    case 'accepted':
      return 'http://maps.google.com/mapfiles/ms/icons/green-dot.png';
    case 'created':
      return 'http://maps.google.com/mapfiles/ms/icons/red-dot.png';
    default:
      return null;
  }
}

const _MissionList = (props: TMissionProps) => {
  if (!props.data.searchMissions) return null
  return (
        props.data.searchMissions &&
        props.data.searchMissions.map( mission => (
            <Marker
                    position={{ lng: mission.location[0], lat: mission.location[1]}}
                    key={ mission.id }
                    title={ mission.title }
                    icon={setIcon(mission.status)}
                    onClick={() => this.handleMissionClick(mission.id)}
            >
            </Marker>
        ))
  )
}

const MissionList = connect(
  ({ session }) => ({ t: 1 })
)(graphql(gql`
    query mapMissions(
      $authToken: String!
    ) {
    searchMissions(
      input: {
        location: [2, 3]
      }
    ) {
      id
      title
      status
    }
  }
`, {
  options: {
    fetchPolicy: 'network-only'
  }
})(_MissionList))

const GoogleMapWrapper = withScriptjs(withGoogleMap((props) =>
    <GoogleMap
      defaultZoom={11}
      defaultCenter={{ lat: 48.8588377, lng: 2.2770201 }}
      center={props.center}
    >
      <MissionList/>
    </GoogleMap>))

export default  class DashboardPage extends React.Component {
  constructor () {
    super();
    this.state = {
      localised: {
        lat: 48.8588377,
        lng: 2.2770201,
        selectedMissionId: null,
        showMissionDetailsLayer: false
      }
    };
  }

  toggleMissionDetailsLayer = () => {
    this.setState({
      showMissionDetailsLayer: !this.state.showMissionDetailsLayer
    })
  }

  componentDidMount () {
    this.getLocation();
  }

  handleMissionClick = (missionId: string) => {
    this.setState({
      selectedMissionId: missionId
    })
    this.toggleMissionDetailsLayer()
  }

  getLocation() {
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition((position) => {
        this.setState({
          localised: {
            lat: position.coords.latitude,
            lng: position.coords.longitude
          }}
        )
      })
    }
  }

  render () {
    return (
      <div>
        <div style={{ height: '20vh', width: '100%' }}>

        </div>

          <GoogleMapWrapper isMarkerShown
                            googleMapURL="https://maps.googleapis.com/maps/api/js?key=$$$&?v=3.exp&libraries=geometry,drawing,places"
                            loadingElement={<div style={{ height: `100%` }} />}
                            containerElement={<div style={{ height: `400px` }} />}
                            mapElement={<div style={{ height: `80vh` }} />}
                            center={{ lat : this.state.localised.lat, lng : this.state.localised.lng }}

          />
        {
          this.state.showMissionDetailsLayer &&
          <Layer align='right' closer={true} overlayClose={true} onClose={this.toggleMissionDetailsLayer}>
            <MissionDetails mission={_(this.props.data.allMissions).find({id: this.state.selectedMissionId})} />
          </Layer>
        }
      </div>
    )
  }
}
/@flow
从“React”导入React
从“反应谷歌地图”导入{withScriptjs,withGoogleMap,GoogleMap,Marker}
从“graphql标记”导入gql
从'react apollo'导入{graphql}
从“react redux”导入{connect}
从“套圈/组件/层”导入层
从“/../missions/details”导入任务详细信息
类型TMission={
id:string,
描述:字符串,
状态:字符串,
标题:字符串,
地点:编号[]
}
类型TMissionProps={
数据:{
加载:布尔,
搜索任务:数组
}
}
功能设置图标(状态){
开关(状态){
“受理”案件:
返回'http://maps.google.com/mapfiles/ms/icons/green-dot.png';
“已创建”案例:
返回'http://maps.google.com/mapfiles/ms/icons/red-dot.png';
违约:
返回null;
}
}
const_任务列表=(道具:t任务道具)=>{
如果(!props.data.searchMissions)返回null
返回(
道具、数据、搜索任务&&
props.data.searchMissions.map(任务=>(
this.handleMissionClick(mission.id)}
>
))
)
}
const MissionList=connect(
({session})=>({t:1})
)(图ql(gql`
查询地图任务(
$authToken:String!
) {
搜索任务(
输入:{
地点:[2,3]
}
) {
身份证件
标题
地位
}
}
`, {
选项:{
fetchPolicy:“仅限网络”
}
})(_特派团名单))
const GoogleMapWrapper=withScriptjs(withGoogleMap((道具)=>
))
导出默认类DashboardPage扩展React.Component{
构造函数(){
超级();
此.state={
本地化:{
拉脱维亚:48.8588377,
液化天然气:2.2770201,
selectedMissionId:null,
showMissionDetailsLayer:错误
}
};
}
toggleMissionDetailsLayer=()=>{
这是我的国家({
showMissionDetailsLayer:!this.state.showMissionDetailsLayer
})
}
组件安装(){
这个.getLocation();
}
handleMissionClick=(任务ID:string)=>{
这是我的国家({
selectedMissionId:missionId
})
this.toggleMissionDetailsLayer()
}
getLocation(){
if(导航器.地理位置){
navigator.geolocation.getCurrentPosition((位置)=>{
这是我的国家({
本地化:{
纬度:位置坐标纬度,
lng:position.coords.longitude
}}
)
})
}
}
渲染(){
返回(
{
这个.state.showMissionDetailsLayer&&
}
)
}
}

因为您的手柄missionclick是在仪表板页面中定义的。它是MissionList的父级之一,您需要通过props传递回调处理程序。这样,任务列表就有了一个处理onClick的道具

在仪表板页面中,应传递onClickHandler

<GoogleMapWrapper 
  isMarkerShown
  googleMapURL="https://maps.googleapis.com/maps/api/js?key=$$$&?v=3.exp&libraries=geometry,drawing,places"
  loadingElement={<div style={{ height: `100%` }} />}
  containerElement={<div style={{ height: `400px` }} />}
  mapElement={<div style={{ height: `80vh` }} />}
  center={{ lat : this.state.localised.lat, lng : this.state.localised.lng }}
  handleMissionClick={this.handleMissionClick} // Add callback prop here
/>

在你的谷歌地图包装器中将手柄missionclick道具传递给任务列表

const GoogleMapWrapper = withScriptjs(withGoogleMap((props) =>
<GoogleMap
  defaultZoom={11}
  defaultCenter={{ lat: 48.8588377, lng: 2.2770201 }}
  center={props.center}
>
  <MissionList handleMissionClick={props.handleMissionClick} />
</GoogleMap>))
const GoogleMapWrapper=withScriptjs(withGoogleMap((props)=>
))
在你的任务道具中,你现在有onClick作为道具

type TMissionProps = {
  data: {
    loading: boolean,
    searchMissions?: Array<TMission>
  },
  onClick: string => void
} 
类型TMissionProps={
数据:{
加载:布尔,
搜索任务:数组
},
onClick:string=>void
} 
更新标记以使用回调属性

 <Marker
   position={{ lng: mission.location[0], lat: mission.location[1]}}
   key={ mission.id }
   title={ mission.title }
   icon={setIcon(mission.status)}
   onClick={() => props.handleMissionClick(mission.id)} // Notice this is now props.handleMissionClick instead of this.handleMissionClick
 >
 </Marker>
props.handleMissionClick(mission.id)}//注意,现在是props.handleMissionClick,而不是this.handleMissionClick
>