在渲染部分之外调用函数
Calling a Function outside the render part
我是 React 和 Apollo (GraphQL) 的新手。当用户点击 google 地图标记时,我需要显示一个图层。我的阿波罗请求根据在数据库中找到的任务正确显示标记,我面临的唯一问题是 onClick 返回 TypeError: _this.handleMissionClick is not a function
。我认为这是因为该函数在渲染部分和主要class之外,并且无法找到link这两个部分的方法。
这是完整的页面代码:
// @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>
)
}
}
由于您的 handleMissionClick 是在 DashboardPage 中定义的。您需要通过道具传递回调处理程序的 MissionList 的父项之一。这样 MissionList 就有一个道具来处理 onClick
在您的 DashboardPage 中,您应该传递一个 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
/>
在您的 GoogleMapWrapper 中将 handleMissionClick 道具传递给 MissionList
const GoogleMapWrapper = withScriptjs(withGoogleMap((props) =>
<GoogleMap
defaultZoom={11}
defaultCenter={{ lat: 48.8588377, lng: 2.2770201 }}
center={props.center}
>
<MissionList handleMissionClick={props.handleMissionClick} />
</GoogleMap>))
在您的 MissionProps 中,您现在将 onClick 作为道具
type TMissionProps = {
data: {
loading: boolean,
searchMissions?: Array<TMission>
},
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>
我是 React 和 Apollo (GraphQL) 的新手。当用户点击 google 地图标记时,我需要显示一个图层。我的阿波罗请求根据在数据库中找到的任务正确显示标记,我面临的唯一问题是 onClick 返回 TypeError: _this.handleMissionClick is not a function
。我认为这是因为该函数在渲染部分和主要class之外,并且无法找到link这两个部分的方法。
这是完整的页面代码:
// @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>
)
}
}
由于您的 handleMissionClick 是在 DashboardPage 中定义的。您需要通过道具传递回调处理程序的 MissionList 的父项之一。这样 MissionList 就有一个道具来处理 onClick
在您的 DashboardPage 中,您应该传递一个 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
/>
在您的 GoogleMapWrapper 中将 handleMissionClick 道具传递给 MissionList
const GoogleMapWrapper = withScriptjs(withGoogleMap((props) =>
<GoogleMap
defaultZoom={11}
defaultCenter={{ lat: 48.8588377, lng: 2.2770201 }}
center={props.center}
>
<MissionList handleMissionClick={props.handleMissionClick} />
</GoogleMap>))
在您的 MissionProps 中,您现在将 onClick 作为道具
type TMissionProps = {
data: {
loading: boolean,
searchMissions?: Array<TMission>
},
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>