请勿在<路由器>之外使用<链接>

时间:2019-07-27 08:48:26

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

所以直到现在我对react-router-dom都没有任何问题,让我解释一下。

我有错误 You should not use <Link> outside a <Router>

<Link />组件中使用Maps时会发生这种情况。 我只是这样使用它:

<Link
   to={`/c/contribution/${this.state.selectedPlace.id}`}>
  <Button>Learn more</Button>
</Link>

但是事实是,这不能在<Router />之外,因为整个应用程序都包裹在其中。

这是我的index.js

ReactDOM.render(
    <Provider store={store}>
        <BrowserRouter>
            <Route path="/c" component={App} />
            <Route path="/login" component={Login} />
            <Route path="/register" component={Register} />
        </BrowserRouter>
    </Provider>,
    document.getElementById('root')
)

导入为:import { BrowserRouter, Route } from 'react-router-dom'

所以这是我的App

return (
                <div className="App">
                    <Route
                        path="/c/contributions"
                        exact
                        component={Contributions}
                    />
                    <Route path="/c/request" exact component={Request} />
                    <Route path="/c/account" exact component={Account} />
                    <Route path="/c/chat" exact component={Chat} />
                    <Route
                        path="/c/contribution/:id"
                        component={Contribution}
                    />
                    <Route path="/c/chatthread/:id" component={ChatThread} />
                    <div className="fader" />
                    <Navbar />
                </div>
            )

因此,在这里您可以清楚地看到<Navbar />在我的App中,component是在此Maps中呈现的:

return (
            <div>
                <Button
                    onClick={this.handleAnimationChange}
                    className="toggle-button"
                >
                    <Icon name="sidebar" size={'big'} />
                </Button>
                <Sidebar
                    as={Menu}
                    animation="overlay"
                    direction="left"
                    icon="labeled"
                    vertical
                    visible={this.state.visible}
                    width="thin"
                    className="navbar"
                >
                    <Link to="/c">
                        <Menu.Item
                            className="nav-item"
                            onClick={this.handleAnimationChange}
                        >
                            <Icon name="map" />
                            Map
                        </Menu.Item>
                    </Link>
                    <Link to="/c/contributions">
                        <Menu.Item
                            className="nav-item"
                            onClick={this.handleFadeChange}
                        >
                            <Icon name="users" />
                            My Contributions
                        </Menu.Item>
                    </Link>
                    <Link to="/c/request">
                        <Menu.Item
                            className="nav-item"
                            onClick={this.handleFadeChange}
                        >
                            <Icon name="paper plane outline" />
                            New Request
                        </Menu.Item>
                    </Link>
                    <Link to="/c/account">
                        <Menu.Item
                            className="nav-item"
                            onClick={this.handleFadeChange}
                        >
                            <Icon name="user" />
                            Account
                        </Menu.Item>
                    </Link>
                    <Link to="/c/chat">
                        <Menu.Item
                            className="nav-item"
                            onClick={this.handleFadeChange}
                        >
                            <Icon name="chat" />
                            Chat
                        </Menu.Item>
                    </Link>
                    <Menu.Item
                        className="nav-item logout-button"
                        onClick={this.logout}
                    >
                        <Icon name="window close" />
                        <strong>Logout</strong>
                    </Menu.Item>
                </Sidebar>
                <Maps />
            </div>
        )

那我为什么会收到此错误?我在许多其他组件中都使用了<Link />,但仅在Maps

中失败了

地图组件:

import React, { Component } from 'react'
import { Map, GoogleApiWrapper, Marker, InfoWindow } from 'google-maps-react'
import { connect } from 'react-redux'
import { saveMapCoords } from '../redux/actions/index'
import { Link } from 'react-router-dom'
import { Button } from 'semantic-ui-react'
const uuidv1 = require('uuid/v1')

export class Maps extends Component {
    state = {
        data: [],
        loc_x: 0,
        loc_y: 0,
        showingInfoWindow: false,
        activeMarker: {},
        selectedPlace: {}
    }

    getUserLocation = () => {
        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(this.showPosition)
        }
    }

    showPosition = position => {
        this.setState({
            loc_x: position.coords.latitude,
            loc_y: position.coords.longitude
        })
    }

    async fetchRequestLocations() {
        await fetch(`http://localhost:3000/requests/`, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'X-User-Email': localStorage.getItem('email'),
                'X-User-Token': localStorage.getItem('token')
            }
        })
            .then(res => res.json())
            .then(data => {
                this.setState({ data: data.data })
            })
    }

    saveCoords = (mapProps, map, clickEven) => {
        if (window.location.pathname === '/c/request') {
            this.props.saveMapCoords(
                clickEven.latLng.lat(),
                clickEven.latLng.lng()
            )
            document.querySelector('.custom-modal').style.visibility = 'visible'
            document.querySelector('.fader').style.visibility = 'visible'
        }
    }

    openContribution = id => {
        window.location.pathname = `/c/contribution/${id}`
    }

    componentDidMount() {
        this.fetchRequestLocations()
        this.getUserLocation()
    }

    render() {
        return (
            <div>
                <Map
                    google={this.props.google}
                    zoom={14}
                    styles={this.props.mapStyles}
                    disableDefaultUI={true}
                    onClick={this.saveCoords}
                    center={{
                        lat: this.state.loc_x,
                        lng: this.state.loc_y
                    }}
                >
                    {this.state.data.map(m => {
                        if (m.status === 'open') {
                            if (m.request_type === 'normal') {
                                return (
                                    <Marker
                                        key={uuidv1()}
                                        position={{ lat: m.x, lng: m.y }}
                                        title={m.title}
                                        data={m}
                                        onClick={this.onMarkerClick}
                                        icon={{
                                            url: '../../data/welfareroom.png',
                                            anchor: new this.props.google.maps.Point(
                                                48,
                                                48
                                            ),
                                            scaledSize: new this.props.google.maps.Size(
                                                48,
                                                48
                                            )
                                        }}
                                    />
                                )
                            } else {
                                return (
                                    <Marker
                                        key={uuidv1()}
                                        position={{ lat: m.x, lng: m.y }}
                                        title={m.title}
                                        data={m}
                                        onClick={this.onMarkerClick}
                                        icon={{
                                            url: '../../data/tortillas1.png',
                                            anchor: new this.props.google.maps.Point(
                                                48,
                                                48
                                            ),
                                            scaledSize: new this.props.google.maps.Size(
                                                48,
                                                48
                                            )
                                        }}
                                    />
                                )
                            }
                        }
                    })}
                    <InfoWindow
                        marker={this.state.activeMarker}
                        visible={this.state.showingInfoWindow}
                    >
                        <div>
                            <h1>{this.state.selectedPlace.title}</h1>
                            <div>{this.state.selectedPlace.description}</div>
                            <Link
                                to={`/c/contribution/${
                                    this.state.selectedPlace.id
                                }`}
                            >
                                <Button>Learn more</Button>
                            </Link>
                        </div>
                    </InfoWindow>
                </Map>
            </div>
        )
    }

    onMarkerClick = (props, marker) => {
        console.log(props.data)
        this.setState({
            selectedPlace: props.data,
            activeMarker: marker,
            showingInfoWindow: true
        })
    }
}

Maps.defaultProps = {
    mapStyles: [
        {
            elementType: 'geometry',
            stylers: [
                {
                    color: '#242f3e'
                }
            ]
        },
        {
            elementType: 'labels.text.fill',
            stylers: [
                {
                    color: '#746855'
                }
            ]
        },
        {
            elementType: 'labels.text.stroke',
            stylers: [
                {
                    color: '#242f3e'
                }
            ]
        },
        {
            featureType: 'administrative.land_parcel',
            elementType: 'labels',
            stylers: [
                {
                    visibility: 'off'
                }
            ]
        },
        {
            featureType: 'administrative.locality',
            elementType: 'labels.text.fill',
            stylers: [
                {
                    color: '#d59563'
                }
            ]
        },
        {
            featureType: 'poi',
            elementType: 'labels.text',
            stylers: [
                {
                    visibility: 'off'
                }
            ]
        },
        {
            featureType: 'poi',
            elementType: 'labels.text.fill',
            stylers: [
                {
                    color: '#d59563'
                }
            ]
        },
        {
            featureType: 'poi.business',
            stylers: [
                {
                    visibility: 'off'
                }
            ]
        },
        {
            featureType: 'poi.park',
            elementType: 'geometry',
            stylers: [
                {
                    color: '#263c3f'
                }
            ]
        },
        {
            featureType: 'poi.park',
            elementType: 'labels.text',
            stylers: [
                {
                    visibility: 'off'
                }
            ]
        },
        {
            featureType: 'poi.park',
            elementType: 'labels.text.fill',
            stylers: [
                {
                    color: '#6b9a76'
                }
            ]
        },
        {
            featureType: 'road',
            elementType: 'geometry',
            stylers: [
                {
                    color: '#38414e'
                }
            ]
        },
        {
            featureType: 'road',
            elementType: 'geometry.stroke',
            stylers: [
                {
                    color: '#212a37'
                }
            ]
        },
        {
            featureType: 'road',
            elementType: 'labels.text.fill',
            stylers: [
                {
                    color: '#9ca5b3'
                }
            ]
        },
        {
            featureType: 'road.highway',
            elementType: 'geometry',
            stylers: [
                {
                    color: '#746855'
                }
            ]
        },
        {
            featureType: 'road.highway',
            elementType: 'geometry.stroke',
            stylers: [
                {
                    color: '#1f2835'
                }
            ]
        },
        {
            featureType: 'road.highway',
            elementType: 'labels.text.fill',
            stylers: [
                {
                    color: '#f3d19c'
                }
            ]
        },
        {
            featureType: 'road.local',
            elementType: 'labels',
            stylers: [
                {
                    visibility: 'off'
                }
            ]
        },
        {
            featureType: 'transit',
            elementType: 'geometry',
            stylers: [
                {
                    color: '#2f3948'
                }
            ]
        },
        {
            featureType: 'transit.station',
            elementType: 'labels.text.fill',
            stylers: [
                {
                    color: '#d59563'
                }
            ]
        },
        {
            featureType: 'water',
            elementType: 'geometry',
            stylers: [
                {
                    color: '#17263c'
                }
            ]
        },
        {
            featureType: 'water',
            elementType: 'labels.text.fill',
            stylers: [
                {
                    color: '#515c6d'
                }
            ]
        },
        {
            featureType: 'water',
            elementType: 'labels.text.stroke',
            stylers: [
                {
                    color: '#17263c'
                }
            ]
        }
    ]
}

function mapStateToProps(state) {
    return {
        x: state.x,
        y: state.y
    }
}

export default connect(
    mapStateToProps,
    { saveMapCoords }
)(
    GoogleApiWrapper({
        apiKey: KEY'
    })(Maps)
)

1 个答案:

答案 0 :(得分:1)

此问题特定于google-maps-react。

地图中InfoWindow的内容是基于UI的语义组件,其中包含利用React Router并最终显示对话框的Button。当前,InfoWindow组件将子级呈现为字符串,并将其设置为infoWindow.setContent(renderedString)的内容。这样,所有事件绑定都将丢失。

检查解决方法https://github.com/fullstackreact/google-maps-react/issues/202