【发布时间】:2018-01-07 19:52:56
【问题描述】:
我正在尝试在 React 中实现外部 API,并希望能够使用 Google Maps 的 API 在子组件中显示地图。理想情况下,我想了解如何在没有任何外部库的情况下做到这一点,以便在使用 Axios 之类的东西之前对流程有一个基本的了解。
我的问题是:如何使用 Google 文档中的以下 sn-p 用于 React 中的 API?
<script async defer
src='https://maps.googleapis.com/maps/api/js?key=AIzaSyDZfVO29Iytspv4xz7S68doIoiztiRLhbk&callback=initMap'>
</script>
我尝试在我的 index.html 文件中使用它,但是当我在 React 的子组件中引用 google 对象时,我得到一个错误:
./src/Main.js 第 114 行:'google' 未定义 no-undef
即使这不是首选或最优雅的方式,我们也非常感谢您对如何在没有任何外部库的情况下实现 API 有一些基本的了解。谢谢!
编辑:
我的 App.js:
import React, { Component } from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
import Main from './Main';
import logo from './logo.svg';
import './App.css';
import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin();
class App extends Component {
render() {
return (
<MuiThemeProvider>
<Main />
</MuiThemeProvider>
);
}
}
export default App;
我的 Main.js:
import React, { Component } from 'react';
import { FlatButton, Dialog, Card, Drawer, Paper, AppBar, Popover, Menu, MenuItem } from 'material-ui';
var items = [
{
id: 0,
name: 'Test 1',
city: 'Toronto',
longitude: 24.42142422,
latitude: 49.24121415,
tags: ['vegan', 'cheap', 'low-calorie'],
reviews: [
{
rating: 5,
reviewText: 'This was an amazing restaurant. Incredibly fast service, a large variety of options, and delicious food. I\'ll be here often',
author: 'Mohammad Sheikh',
date: new Date(),
helpfulCount: 5,
notHelpfulCount: 4
},
{
rating: 2,
reviewText: 'Absolutely horrible. Please stop making food.',
author: 'Dissatisfied Customer',
date: new Date(),
helpCount: 2,
notHelpfulCount: 3
},
],
foods:
[
{
id: 0,
name: 'Salad',
img: 'http://www.images.google.com/',
tags: ['vegan', 'low-calorie', 'cheap'],
nutrition:
{
calories: 300,
fat: 5,
carbs: 40,
protein: 24
},
reviews:
{
rating: 4,
reviewText: 'Decent salad. Would recommend.',
author: 'Vegan Bro',
date: new Date(),
helpCount: 4,
notHelpfulCount: 1
}
},
{
id: 1,
name: 'Pasta',
img: 'http://www.images.google.com/',
tags: ['vegetarian', 'dinner'],
nutrition:
{
calories: 800,
fat: 40,
carbs: 80,
protein: 20
},
reviews:
{
rating: 5,
reviewText: 'Absolutely amazing',
author: 'Food Fan',
date: new Date(),
helpCount: 8,
notHelpfulCount: 4
}
},
],
},
];
const paperStyle = {
height: 100,
width: 100,
margin: 20,
textAlign: 'center',
display: 'table',
position: 'relative',
clear: 'both',
float: 'right',
zIndex: 6
};
const paperContent = {
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)'
}
class RestaurantDialog extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false
}
}
render() {
return (
<Dialog>
</Dialog>
)
}
}
class RestaurantButton extends React.Component {
constructor(props) {
super(props);
}
handleClick = () => {
}
render() {
return (
<FlatButton style={{width: '100%', height: '64px'}} onClick>
{this.props.item.city}
<RestaurantDialog restaurant={this.props.item.name} />
</FlatButton>
)
}
}
class MapComponent extends React.Component {
constructor(props) {
super(props);
this.googleChecker = this.googleChecker.bind(this);
this.renderMap = this.renderMap.bind(this);
}
googleChecker() {
if (!window.google.maps) {
setTimeout(this.googleChecker, 100);
}
else {
this.renderMap();
}
}
renderMap() {
var map = google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: {lat: 0, lng: 0}
});
}
componentDidMount() {
this.googleChecker();
}
render() {
const selections = this.props.currentSelections;
const buttons = items.filter((item) => {
for (let i = 0; i < selections.length; i++) {
if (selections.map((selection) => {return selection.toLowerCase()}).indexOf(item.tags[i].toLowerCase()) > -1) {
return true;
}
}}).map((item) => {
return (
<RestaurantButton style={{zIndex: '5'}} item={item} />
)
});
return (
<Paper id='map' zDepth={3} style={{height: '300px', width: '100%', backgroundColor: 'white', position: 'absolute'}}>
{ buttons }
</Paper>
)
}
}
class SelectionIcon extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<Paper circle={true} zDepth={5} style={this.props.style} key={this.props.index} onClick={this.props.close} >
<div style={paperContent}>{this.props.item}</div>
</Paper>
)
}
}
class SelectionIcons extends React.Component {
constructor(props) {
super(props);
}
handleSelectionClose = (e) => {
e.currentTarget.open = false;
}
render() {
let currentSelections = this.props.currentSelections.slice();
let list = currentSelections.map((item, i) => {
return (
<Paper circle={true} zDepth={5} style={paperStyle} key={i} onClick={this.handleSelectionClose}>
<div style={paperContent}>{item}</div>
</Paper>
)
});
return (
<div>
{list}
</div>
)
}
}
class Main extends React.Component {
constructor(props){
super(props);
this.state = {
navMenuOpen: false,
currentSelections: []
}
}
handleMenuButtonTouch = (e) => {
this.setState({
anchorEl: e.currentTarget.parentNode,
navMenuOpen: !this.state.navMenuOpen
})
}
handleRequestChange = (change) => {
this.setState({
navMenuOpen: change.open
})
console.log(document.getElementById('test').style);
}
handleMenuClick = (e) => {
let currentSelections = this.state.currentSelections.slice();
if (currentSelections.indexOf(e) > -1) {
currentSelections.splice(currentSelections.indexOf(e), 1);
}
else {
currentSelections.push(e);
}
console.log(currentSelections)
this.setState({ currentSelections });
}
render() {
return (
<div>
<AppBar title='The App' id='test' zDepth={1} onLeftIconButtonTouchTap={this.handleMenuButtonTouch} style={{zIndex: 4}}>
</AppBar>
<Drawer
id='test2'
open={this.state.navMenuOpen}
onRequestChange={() => {this.handleRequestChange;}}
containerStyle={{zIndex: 3, marginTop: '64px'}}>
<Menu>
<MenuItem primaryText='High Protein' onClick={() => this.handleMenuClick('High Protein')} />
<MenuItem primaryText='Vegetarian' onClick={() => this.handleMenuClick('Vegetarian')} />
<MenuItem primaryText='Vegan' onClick={() => this.handleMenuClick('Vegan')} />
</Menu>
</Drawer>
<MapComponent items={items} currentSelections={this.state.currentSelections} />
<SelectionIcons currentSelections={this.state.currentSelections} />
</div>
)
}
}
export default Main;
我的 index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<script async defer
src='https://maps.googleapis.com/maps/api/js?key=AIzaSyDZfVO29Iytspv4xz7S68doIoiztiRLhbk'>
</script>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
【问题讨论】:
标签: javascript ajax google-maps reactjs google-maps-api-3