不变式失败:您不应将<Router>外的<Route>与GoogleMap API一起使用

时间:2019-12-30 04:04:55

标签: reactjs react-router-v4 react-router-dom

我试图在对话框中添加一个“选择按钮”,该对话框使用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)),
          );
        },
      ),
    ),
 )```

1 个答案:

答案 0 :(得分:0)

使用google-maps-react在地图上进行渲染会受到一些限制,因为地图的子级是如何渲染的。我做了一个小测试项目,并说google-maps-reactreact-router有点不兼容。

如果您想更深入地研究,可以使用React开发工具查看在React组件方面呈现的内容。

我认为使用google-maps-react的方法是附加点击处理程序,但这会使使用react-router的工作更加复杂。

对于一条更简单的路径,您可以尝试使用google-map-react软件包。它的工作方式略有不同,但是可以轻松在地图上渲染几乎所有内容。