Ich habe eine Sidebar mit zwei Tasten, "Test" und "über". Test (Raketensymbol) wird bei '/ test' gerendert und Über (Home-Symbol) wird bei '/' gerendert.React-Router v4 Rendering falsche Komponente, aber richtig zusammenpassen
Sie befinden sich beide im Stamm der App und sind in einer Komponente verschachtelt.
Wenn ich bei '/' starte und auf den Link zu = "/ test" klicke, wird immer die 'About' Komponente geladen, und wenn ich die Props für die KomponenteDidMount von 'About' überprüfe, enthält das Match-Objekt Matchdaten für "/ test".
Nur wenn ich sie aktualisiere, wird die richtige Komponente, 'Test', wieder angezeigt. Irgendeine Idee, warum das passiert?
AppRoutes.js:
export class AppRoutes extends React.Component {
render() {
return (
<div>
<Switch>
<Route
exact path="/"
render={(matchProps) => (
<LazyLoad getComponent={() => import('pages/appPages/About')} {...matchProps} />
)}
/>
<Route
path="/login"
render={(matchProps) => (
<LazyLoad getComponent={() => import('pages/appPages/Login')} {...matchProps} />
)}
/>
<Route
path="/register"
render={(matchProps) => (
<LazyLoad getComponent={() => import('pages/appPages/Register')} {...matchProps} />
)}
/>
<Route
path="/test"
render={(matchProps) => (
<LazyLoad getComponent={() => import('pages/appPages/Test')} {...matchProps} />
)}
/>
...
AboutPage.js & & TestPage.js (Duplikate Ausnahme Komponentenname):
import React from 'react';
import SidebarContainer from 'containers/SidebarContainer';
import SidebarPageLayout from 'styles/SidebarPageLayout';
export const About = (props) => {
console.log('About Loading: ', props);
return (
<SidebarPageLayout>
<SidebarContainer />
<div>About</div>
</SidebarPageLayout>
);
}
export default About;
SidebarContainer.js:
import React from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';
import Sidebar from 'sidebar/Sidebar';
import HamburgerButton from 'sidebar/HamburgerButton';
import AboutButton from 'sidebar/AboutButton';
import ProfileButton from 'sidebar/ProfileButton';
import TestButton from 'sidebar/TestButton';
export class SidebarContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
sidebarIsOpen: false,
sidebarElements: [],
};
}
componentDidMount() {
if (!this.props.authenticated) {
this.setState({
sidebarElements: _.concat(this.state.sidebarElements, HamburgerButton, ProfileButton, AboutButton, TestButton),
});
}
}
toggleSidebarIsOpenState =() => {
this.setState({ sidebarIsOpen: !this.state.sidebarIsOpen });
}
render() {
const { authenticated, sidebarIsOpen, sidebarElements} = this.state;
return (
<div>
<Sidebar
authenticated={authenticated}
sidebarIsOpen={sidebarIsOpen}
sidebarElements={_.isEmpty(sidebarElements) ? undefined: sidebarElements}
toggleSidebarIsOpenState={this.toggleSidebarIsOpenState}
/>
</div>
);
}
}
SidebarContainer.propTypes = {
authenticated: PropTypes.bool,
};
export default SidebarContainer;
Sidebar .js:
import React from 'react';
import _ from 'lodash';
import PropTypes from 'prop-types'
import SidebarStyles from '../styles/SidebarStyles';
export const Sidebar = (props) => {
if (props && props.sidebarElements) {
return (
<SidebarStyles sidebarIsOpen={props.sidebarIsOpen}>
{_.map(props.sidebarElements, (value, index) => {
return React.createElement(
value,
{
key: index,
authenticated: props.authenticated,
sidebarIsOpen: props.sidebarIsOpen,
toggleSidebarIsOpenState: props.toggleSidebarIsOpenState,
},
);
})}
</SidebarStyles>
);
}
return (
<div></div>
);
}
Sidebar.propTypes = {
authenticated: PropTypes.bool,
sidebarIsOpen: PropTypes.bool,
sidebarElements: PropTypes.array,
toggleSidebarIsOpenState: PropTypes.func,
};
export default Sidebar;
TestButton.js:
import React from 'react';
import PropTypes from 'prop-types';
import Icon from 'react-fontawesome';
import {
Link
} from 'react-router-dom';
export const TestButton = (props) => {
return (
<Link to="/test">
<Icon name='rocket' size='2x' />
</Link>
);
}
export default TestButton;
AboutButton.js:
import React from 'react';
import PropTypes from 'prop-types';
import Icon from 'react-fontawesome';
import {
Link
} from 'react-router-dom';
export const AboutButton = (props) => {
return (
<Link to="/">
<Icon name='home' size='2x' />
</Link>
);
}
export default AboutButton;
keine Auffrischung, nur konstant Klicken auf den '/ test' Weg vom '/' Route:
nach Aktualisierung:
Edit:
Wurzelkomponenten:
Edit:
store.js:
import {
createStore,
applyMiddleware,
compose,
} from 'redux';
import createSagaMiddleware from 'redux-saga';
import { rootReducer } from './rootReducers';
import { rootSaga } from './rootSagas';
// sagas
const sagaMiddleware = createSagaMiddleware();
// dev-tools
const composeEnhancers = typeof window === 'object' && (
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? (
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
) : compose
);
export function configureStore() {
const middlewares = [
sagaMiddleware,
];
const store = createStore(
rootReducer,
{},
composeEnhancers(applyMiddleware(...middlewares))
);
sagaMiddleware.run(rootSaga);
return store;
}
export const store = configureStore();
index.js (root):
import React from 'react';
import { Provider } from 'react-redux';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { store } from './store';
import AppContainer from 'containers/AppContainer';
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<AppContainer />
</BrowserRouter>
</Provider>,
document.getElementById('root')
);
AppContainer:
import React from 'react';
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import { logout, verifyToken } from './actions';
import { selectAuthenticated, selectAuthenticating } from './selectors';
import AppRoutes from 'routes/AppRoutes';
export class AppContainer extends React.Component {
constructor(props) {
super(props);
this.state = { loaded: false };
}
componentDidMount() {
const token = localStorage.getItem('jwt');
if (token) {
this.props.verifyToken(token,() => this.setState({ loaded: true }));
} else {
this.setState({ loaded: true });
}
}
render() {
if (this.state.loaded) {
return (
<AppRoutes
authenticated={this.props.authenticated}
authenticating={this.props.authenticating}
logout={this.props.logout}
/>
);
} else {
return <div>Loading ...</div>
}
}
}
function mapStateToProps(state) {
return {
authenticated: selectAuthenticated(state),
authenticating: selectAuthenticating(state),
};
}
function mapDispatchToProps(dispatch) {
return {
verifyToken: (token = '', callback = false) => dispatch(verifyToken(token, callback)),
logout:() => dispatch(logout()),
};
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(AppContainer));
Edit 2 für LazyLoad:
services/LazyLoad/index.js:
import React from 'react';
export class LazyLoad extends React.Component {
constructor(props) {
super(props);
this.state = {
AsyncModule: null,
};
}
componentDidMount() {
this.props.getComponent() // getComponent={() => import('./someFile.js')}
.then(module => module.default)
.then(AsyncModule => this.setState({AsyncModule}))
}
render() {
const { loader, ...childProps } = this.props;
const { AsyncModule } = this.state;
if (AsyncModule) {
return <AsyncModule {...childProps} />;
}
if (loader) {
const Loader = loader;
return <Loader />;
}
return null;
}
}
export default LazyLoad;
Ich hatte gestern ein ähnliches Problem bei meinem Projekt. Mein hatte eine umhüllende untergeordnete Komponente , die redux verwendete und dies blockierte das erneute Rendern. Es wurde behoben, indem 'connect (...) (TopLayout) 'in' withRouter (connect (...) (TopLayout)) 'geändert wurde, damit es bei jeder Änderung der Route erneut gerendert wird. Mehr Infos hier: https://reacttraining.com/reac-router/web/api/withRouter. Sie zeigen uns nicht Ihre Implementierung, also bin ich mir nicht sicher, dass es das gleiche Problem ist. –
Das fühlt sich so ähnlich an wie die richtige Antwort und ich möchte, dass es wahr ist, aber es funktioniert immer noch nicht für mich. Ich ging rüber und wickelte jeden Container und jede Komponente ein, die einen connect() - Aufruf mit withRouter hatten und es gibt mir immer noch den Fehler. –
Dies könnte wegen 'LazyLoad' sein. Können Sie den 'LazyLoad' Code teilen? –