Много антишаблонного кода, плохая структура приложения и смешивание пакетов сдерживают ваше приложение.
Я полностью переписал его, вот что я сделал:
- Переконфигурировал структуру папки вашего приложения, чтобы она стала стандартной.
- Не смешивайте
Router
(BrowserRouter
) с ConnectedRouter
. - Не размещайте все свои
components
в файле App.js
. - Поскольку
Header
всегда монтируется, вам не нужен redux
, вместо этого вы можете просто использовать withRouter
(он предоставляет маршрутные реквизиты для компонента). - В вашем
rootReducer
отсутствует reducer
, поэтому я добавил dummyReducer
, который просто возвращает state
. - Придерживайтесь
Link
или this.props.history
при навигации.Для этого примера нет необходимости использовать оба.Кроме того, вам не нужно использовать функцию ConnectedRouter
push
, так как history
передается как опора при использовании withRouter
.
. Примечание: если вы хотитеЕсли Header
будет «маршрутизатором», через который проходят все изменения маршрута, то вам нужно будет создать action
и reducer
, которые передадут string
и сохранят его в store
для избыточности.Header
затем connect
редактируется в хранилище приставок и обновляет route
, когда это string
изменилось.
Рабочий пример: https://codesandbox.io/s/526p7kjqq4
компоненты/Header.js
import React, { PureComponent, Fragment } from "react";
import { withRouter } from "react-router-dom";
class Header extends PureComponent {
goTo = route => {
this.props.history.push(route);
};
render = () => (
<Fragment>
<ul>
<li>
<button onClick={() => this.goTo("/")}> Announcements </button>
</li>
<li>
<button onClick={() => this.goTo("/shopping")}> Shopping </button>
</li>
</ul>
<div>
<button onClick={() => this.goTo("/shopping")}>
Click here to go shopping ! (if you can...)
</button>
</div>
</Fragment>
);
}
export default withRouter(Header);
router / index.js
import React from "react";
import { Switch, Route } from "react-router-dom";
import Announcements from "../components/annoucements";
import Shopping from "../components/shopping";
export default () => (
<div style={{ padding: "150px" }}>
<Switch>
<Route exact path="/" component={Announcements} />
<Route path="/shopping" component={Shopping} />
</Switch>
</div>
);
компонентов / App.js
import React, { Fragment } from "react";
import Routes from "../routes";
import Header from "./Header";
export default () => (
<Fragment>
<Header />
<Routes />
</Fragment>
);
Вот что вы пытаетесь сделать: https://codesandbox.io/s/8nmp95y8r2
Однако я НЕ рекомендую это, так как это немного излишне, когда history
либо уже передан как реквизит из Route
, либо может быть выставлен при использовании withRouter
.Согласно Redux docs , это тоже не рекомендуется.И вместо этого либо использовать Link
, либо передавать реквизит history
создателю redux action
вместо программной навигации по состоянию избыточности.
Containers / Header.js
import React, { PureComponent, Fragment } from "react";
import { connect } from "react-redux";
import { push } from "connected-react-router";
class Header extends PureComponent {
goTo = route => this.props.push(route); // this is equivalent to this.props.dispatch(push(route)) -- I'm just appending dispatch to the push function in the connect function below
render = () => (
<Fragment>
<ul>
<li>
<button onClick={() => this.goTo("/")}> Announcements </button>
</li>
<li>
<button onClick={() => this.goTo("/shopping")}> Shopping </button>
</li>
</ul>
<div>
<button onClick={() => this.goTo("/shopping")}>
Click here to go shopping ! (if you can...)
</button>
</div>
</Fragment>
);
}
export default connect(
null,
{ push }
)(Header);