我试图在对话框中添加一个“选择按钮”,该对话框使用CompareDialog.js
内部的Google Map API从组件中弹出。我已经在ClinicMap.js
上实现了相同的“选择按钮”,但是由于某种原因,它在这里有效,但在Invariant failed: You should not use <Route> outside a <Router>
上却无效。我收到错误import React, { Fragment, Component } from "react";
import { Map, GoogleApiWrapper, Marker } from "google-maps-react";
import PcDialog from "../PcDialog";
import Button from "@material-ui/core/Button";
import InfoWindowEx from "./InfoWindowEx";
import { Link, Redirect } from "react-router-dom";
const mapStyles = {
width: "100%",
height: "100%"
};
export class ClinicMap extends Component {
state = {
activeMarker: {},
selectedPlace: {
clinic: {
type: ""
}
},
showingInfoWindow: false
};
onMarkerClick = (props, marker) =>
this.setState({
activeMarker: marker,
selectedPlace: props,
showingInfoWindow: true
});
render() {
const { GP, PC, parentCallback } = this.props;
const { selectedPlace } = this.state;
const displayCurrent = (
<Marker
clinic={{type: "currentloc"}}
position={{
lat: this.props.coord[1],
lng: this.props.coord[0]
}}
/>
);
const displayGP = GP.map(clinic => {
clinic.type = "GP";
clinic.name = clinic.properties.HCI_NAME;
clinic.price = "$$";
clinic.rating = "4.3";
clinic.doctorName = clinic.properties.DR_NAME;
clinic.formattedOpeningHours = clinic.properties.ALL_OPENING_HOURS.map(
period =>
period.day_string + ":</br>" + period.opening_hours.join(",</br>")
).join("</br></br>");
clinic.formattedDirections = clinic.properties.ALL_DIRECTIONS.map(
path => path.transport_string + "</br>" + path.directions.join(",</br>")
).join("</br></br>");
return (
<Marker
key={clinic.id}
clinic={clinic}
id={clinic.id}
icon={"http://maps.google.com/mapfiles/ms/icons/green.png"}
position={{
lat: clinic.geometry.coordinates[1],
lng: clinic.geometry.coordinates[0]
}}
onClick={this.onMarkerClick}
/>
);
});
const displayPC = PC.map(clinic => {
clinic.type = "Polyclinic";
clinic.name = clinic.Name;
clinic.price = "$";
clinic.rating = "4.0";
return (
<Marker
key={clinic.id}
clinic={clinic}
id={clinic.id}
icon={"http://maps.google.com/mapfiles/ms/icons/blue.png"}
position={{
lat: clinic.coord[1],
lng: clinic.coord[0]
}}
onClick={this.onMarkerClick}
>
<PcDialog clinic={clinic} />
</Marker>
);
});
return (
<Map
google={this.props.google}
zoom={15}
style={mapStyles}
initialCenter={{ lat: this.props.coord[1], lng: this.props.coord[0] }}
>
{displayGP}
{displayPC}
{displayCurrent}
{console.log(displayCurrent)}
<InfoWindowEx
marker={this.state.activeMarker}
onClose={this.onInfoWindowClose}
visible={this.state.showingInfoWindow}
selectedPlace={selectedPlace}
>
{selectedPlace.clinic.type === "GP" ? (
<div>
GP:
//some other data
<hr /> Telephone: {selectedPlace.clinic.properties.Tel} <hr />
Applicable subsidies:{" "}
{selectedPlace.clinic.properties.CLINIC_PROGRAMME_CODE.join(", ")}
<hr />
Distance:
{parseFloat(selectedPlace.clinic.distance).toFixed(2)}km away
<hr />
Doctor: {selectedPlace.clinic.properties.DR_NAME}
<hr />
<p>Opening Hours:</p>
<hr />
{
selectedPlace.clinic.properties.ALL_OPENING_HOURS.map(period => (
<p>
{period.day_string}
<br />
{period.opening_hours.join(", ")}
</p>
))
}
<hr />
<p>Directions:</p>
{
selectedPlace.clinic.properties.ALL_DIRECTIONS.map(path => (
<p>
{path.transport_string}
<br />
{path.directions.join(", ")}
</p>
))
}
<hr />
<img src={process.env.PUBLIC_URL + `/ClinicPictures/${selectedPlace.clinic.properties.FILE_NAME}.png`}
alt="clinic picture" style={{ width: "100%" }} />
<hr />
<Button>
<Link
to={{
pathname: "/ConfirmClinicChoice",
state: {
choice: selectedPlace.clinic
}
}}
>
<span>Select</span>
</Link>
</Button>
<Button
variant="contained"
color="primary"
onClick={() =>
this.props.callbackFunction(selectedPlace.clinic)
}
>
{console.log(selectedPlace.clinic)}
<span style={{ color: "white" }}>Add to comparison</span>
</Button>
</div>
) : selectedPlace.clinic.type === "Polyclinic" ? (
<div>
//some other data
<hr /> Telephone: {selectedPlace.clinic.Tel} <hr /> Distance:{" "}
{parseFloat(selectedPlace.clinic.distance).toFixed(2)}km away
<hr />
<Button>
<Link
to={{
pathname: "/ConfirmClinicChoice",
state: {
choice: selectedPlace.clinic
}
}}
>
<span>Select</span>
</Link>
</Button>
<Button
variant="contained"
color="primary"
onClick={() =>
this.props.callbackFunction(selectedPlace.clinic)
}
>
<span style={{ color: "white" }}>Add to comparison</span>
</Button>
</div>
) : (
<div>Input Location</div>
)}
</InfoWindowEx>
</Map>
);
}
}
export default GoogleApiWrapper({
apiKey: ""
})(ClinicMap);
,并提到了this,但不了解该解决方案如何应用于我的上下文。
有人可以启发我解决此问题的方法吗?
这里有一些相关代码,请随时澄清。
ClinicMap.js
import React, { Component, Fragment } from "react";
import Dialog from "@material-ui/core/Dialog";
import { Link } from "react-router-dom";
import Button from "@material-ui/core/Button";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import TableFooter from "@material-ui/core/TableFooter";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
import MyButton from "../../util/MyButton";
import {
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
Typography
} from "@material-ui/core";
import { maxWidth, fontSize } from "@material-ui/system";
export class CompareDialog extends Component {
state = {
open: false,
priceOpen: false,
userNationality: this.props.formData.nationality,
userAge: this.props.formData.age,
userSubsidyType: this.props.formData.subsidyType
};
handleToggle = () => {
this.setState({
open: !this.state.open
});
};
handlePriceToggle = () => {
this.setState({
priceOpen: !this.state.priceOpen
});
};
render() {
const {
open,
priceOpen,
userNationality,
userAge,
userSubsidyType
} = this.state;
const { clinicOne, clinicTwo, formData } = this.props;
function createData(name, gp, pc) {
return { name, gp, pc };
}
const rows = [
createData(
<span style={{ fontWeight: "bold" }}>Name</span>,
<span style={{ fontWeight: "bold" }}>{clinicOne.name}</span>,
<span style={{ fontWeight: "bold" }}> {clinicTwo.name}</span>
),
createData(
"Distance",
parseFloat(clinicOne.distance).toFixed(2),
parseFloat(clinicTwo.distance).toFixed(2)
),
createData("Price", clinicOne.price, clinicTwo.price),
createData("Ratings", clinicOne.rating, clinicTwo.rating),
createData("Doctor name", ((clinicOne.type === "GP") ? clinicOne.doctorName : ""),
((clinicTwo.type === "GP") ? clinicTwo.doctorName : "")),
createData(
"Opening hours",
clinicOne.type === "GP" ? (
<div
dangerouslySetInnerHTML={{
__html: clinicOne.formattedOpeningHours
}}
/>
) : (
""
),
clinicTwo.type === "GP" ? (
<div
dangerouslySetInnerHTML={{
__html: clinicTwo.formattedOpeningHours
}}
/>
) : (
""
)
),
createData(
"Directions",
clinicOne.type === "GP" ? (
<div
dangerouslySetInnerHTML={{
__html: clinicOne.formattedDirections
}}
/>
) : (
""
),
clinicTwo.type === "GP" ? (
<div
dangerouslySetInnerHTML={{
__html: clinicTwo.formattedDirections
}}
/>
) : (
""
)
)
];
//some data irrelevant to the problem
const handleToggle = () => {
this.setState({
open: !this.state.open
});
};
const handlePriceToggle = () => {
this.setState({
priceOpen: !this.state.priceOpen
});
};
return clinicOne === null || clinicTwo === null ? (
"Please select 2 clinics for comparison."
) : (
<div>
<Button
variant="contained"
style={{ backgroundColor: "#ff7c01" }}
onClick={handleToggle}
>
Compare!
</Button>
<Dialog
style={{ fontSize: "1vw" }}
open={open}
onClose={handleToggle}
maxWidth="lg"
>
<DialogContent>
<Table>
<TableHead>
<TableRow>
<TableCell> </TableCell>
<TableCell align="right">{clinicOne.type} </TableCell>
<TableCell align="right">{clinicTwo.type} </TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows.map(row => (
<TableRow key={row.name}>
<TableCell component="th" scope="row">
{row.name === "Price" ? (
<Fragment>
Price
<MyButton
onClick={handlePriceToggle}
tip="More Details"
>
<Typography variant="subtitle1">Expand</Typography>
<ExpandMoreIcon />
</MyButton>
<Dialog open={priceOpen} onClose={handlePriceToggle}>
<DialogContent>
<p
style={{
fontWeight: "bold",
textDecoration: "underline"
}}
>
Cost Breakdown
</p>
<Table>
<TableHead>
<TableRow>
<TableCell />
<TableCell
style={{ minWidth: 200, maxWidth: 200 }}
align="right"
>
{" "}
{clinicOne.type}
</TableCell>
<TableCell
style={{ minWidth: 200, maxWidth: 200 }}
align="right"
>
{clinicTwo.type}
</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell component="th" scope="row">
<span style={{ fontWeight: "bolder" }}>
Name
</span>
</TableCell>
<TableCell component="th" scope="row">
<span style={{ fontWeight: "bolder" }}>
{clinicOne.name}
</span>
</TableCell>
<TableCell component="th" scope="row">
<span style={{ fontWeight: "bolder" }}>
{" "}
{clinicTwo.name}
</span>
</TableCell>
</TableRow>
{priceRows.map(row => (
<TableRow key={row.name}>
<TableCell component="th" scope="row">
{row.name}
</TableCell>
<TableCell align="right">
{clinicOne.type === "GP"
? row.gp
: row.pc}
</TableCell>
<TableCell align="right">
{clinicTwo.type === "GP"
? row.gp
: row.pc}{" "}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</DialogContent>
</Dialog>
</Fragment>
) : (
<Fragment>{row.name}</Fragment>
)}
</TableCell>
<TableCell align="right">{row.gp}</TableCell>
<TableCell align="right">{row.pc} </TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableCell align="right">
<Button />
</TableCell>
<TableCell align="right">
<Button
variant="contained"
style={{ backgroundColor: "#ff7c01" }}
>
<Link
to={{
pathname: "/ConfirmClinicChoice",
state: {
choice: clinicOne,
formData: this.props.formData
}
}}
>
<span style={{ color: "white" }}>Select</span>
</Link>
</Button>
</TableCell>
<TableCell align="right">
<Button
// style={{ fontSize: "1vw" }}
variant="contained"
style={{ backgroundColor: "#ff7c01" }}
>
<Link
to={{
pathname: "/ConfirmClinicChoice",
state: {
choice: clinicTwo,
formData: this.props.formData
}
}}
>
<span style={{ color: "white" }}>Select</span>
</Link>
</Button>
</TableCell>
</TableFooter>
</Table>
</DialogContent>
</Dialog>
</div>
);
}
}
export default CompareDialog;
CompareDialog.js
import React from "react";
import Login from "./pages/Welcome";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import Language from "./pages/Language";
import GeneralInfo from "./pages/GeneralInfo";
import Form from "./pages/PatientForm";
import FilteredResult from "./pages/FilteredResult";
import ConfirmClinicChoicePage from "./pages/ConfirmClinicChoice";
import confirmedChoicePage from "./pages/SummaryPage";
class App extends React.Component {
render() {
return (
<Router>
<div>
<Switch>
<Route path="/" exact component={Login} />
<Route path="/Language" exact component={Language} />
<Route path="/GeneralInfo" exact component={GeneralInfo} />
<Route path="/Form" exact component={Form} />
<Route path="/FilteredResult" exact component={FilteredResult} />
<Route path="/ConfirmClinicChoice" exact component={ConfirmClinicChoicePage} />
<Route path="/confirmedChoice" exact component={confirmedChoicePage} />
</Switch>
</div>
</Router>
);
}
}
export default App;
App.js
{
"name": "pathway",
"version": "0.1.0",
"private": true,
"dependencies": {
"@material-ui/core": "^4.1.3",
"@material-ui/icons": "^4.2.1",
"@turf/distance": "^6.0.1",
"@turf/turf": "^5.1.6",
"bootstrap": "^4.3.1",
"bootstrap-less": "^3.3.8",
"google-maps-react": "^2.0.2",
"jw-react-pagination": "^1.1.0",
"material-ui": "^0.20.2",
"react": "^16.8.6",
"react-bootstrap": "^1.0.0-beta.9",
"react-dom": "^16.8.6",
"react-js-pagination": "^3.0.2",
"react-paginate": "^6.3.0",
"react-router-dom": "^5.0.1",
"react-scripts": "3.0.1",
"react-select": "^3.0.4",
"react-swipeable-views": "^0.13.3",
"turf": "^3.0.14"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"html-loader": "^0.5.5"
}
}
package.json
Positioned(
top: mqHeight / 4.5,
left: 0, /// <-- fixed here
right: 0, /// <-- fixed here
child: SizedBox(
height: 100,
child: ListView.builder(
physics: ClampingScrollPhysics(),
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
return Container(
width: 100,
child: Card(
elevation: 10,
child: Icon(Icons.card_giftcard)),
);
},
),
),
)```
答案 0 :(得分:0)
使用google-maps-react
在地图上进行渲染会受到一些限制,因为地图的子级是如何渲染的。我做了一个小测试项目,并说google-maps-react
和react-router
有点不兼容。
如果您想更深入地研究,可以使用React开发工具查看在React组件方面呈现的内容。
我认为使用google-maps-react
的方法是附加点击处理程序,但这会使使用react-router
的工作更加复杂。
对于一条更简单的路径,您可以尝试使用google-map-react
软件包。它的工作方式略有不同,但是可以轻松在地图上渲染几乎所有内容。