nested routing isn't working with react-router - javascript

I've been trying to render out CollectionPage and match the url with my page but my nested Route that's calling CollectionPage doesn't work for some reason!
here's a snippet from my shop.component that is being called at app.js
import React from 'react';
import { Route } from 'react-router-dom';
import CollectionOverview from '.././../components/collections-overview/collections-overview.component';
import CollectionPage from '../collection/collection.component';
const ShopPage = ({ match }) => (
<div className='shop-page'>
<Route exact path={`${match.path}`} component={CollectionOverview} />
<Route path={`${match.path}/:collectionId`} component={CollectionPage} />
</div>
);
export default ShopPage;

When I did this course an issue I had was that in App.js I had set exact for the shop route. Maybe you have it too :D

I found out what was going on, in my app.js I accidentally set my path='/shop/' so I just had to remove that 2nd '/'

Related

Did not expect server HTML to contain a <div> in <main>

I'm working in a project that uses:
react/react-dom#16.9.0
#loadable/component
styled-components
react-router-dom
The application renders both server side and client side.
I'm using #loadable/component to dynamically code split this way.
router.tsx
import * as React from 'react'
import loadable from '#loadable/component'
import { Route, Switch } from 'react-router-dom'
const NotFound = loadable(() =>
import('../components/NotFound/NotFound' /* webpackChunkName: "notfound" */)
)
const routes = (
<Switch>
<Route component={NotFound} />
</Switch>
)
export default routes
When loading the page, this error appear on the console and the page seems to flick for a second.
react-dom.development.js:546 Warning: Did not expect server HTML to contain a <div> in <main>.
When I check the output in both sides (server/client), they are identical.
When I remove #loadable/component like bellow, it works and the error is gone.
router-without-loadable.tsx
import * as React from 'react'
import { Route, Switch } from 'react-router-dom'
import NotFound from '../components/NotFound/NotFound'
const routes = (
<Switch>
<Route component={NotFound} />
</Switch>
)
export default routes
Seems to be something to do with #loadable/component but I'm not 100% sure.
Finally have an answer for this:
For #loadable/component to work properly, you need to put the magic webpack comment (/* webpackChunkName: "notfound" */) before the path of the file this way.
const NotFound = loadable(() =>
import(/* webpackChunkName: "notfound" */ '../components/NotFound/NotFound')
)
Reference:
https://github.com/smooth-code/loadable-components/issues/23
And more important, in the server side, you need to wrap you app in a ChunkExtractorManager and pass the client extractor (I was passing the server extractor, it's not very clear in the docs).
const statsFile = path.resolve('./wwwroot/dist/loadable-stats.json')
const extractor = new ChunkExtractor({
statsFile,
entrypoints: ['client'] // name of the proper webpack endpoint (default: main)
})
<ChunkExtractorManager extractor={extractor}>
<App />
</ChunkExtractorManager>
Here is a proper clear example on how to implement it:
https://github.com/iamssen/seed
Update 24.09.2019
Added to the official docs
https://www.smooth-code.com/open-source/loadable-components/docs/server-side-rendering/#chunkextractor-entrypoints
I think the problem is your NotFound component is not loaded and thus Route dont know what to render which is causing the error.
You would need to modify something like below:
<Route path="/404/" exact component={props => <NotFound {...props} />} />

Unable to pass props to component through react-router

I am unable to pass props using react-router. My code till now:
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import 'normalize.css/normalize.css';
import './styles/styles.scss';
const EditExpensePage = props => {
console.log(props);
return <div>Editing the expense with id of </div>;
};
const AppRouter = () => {
return (
<BrowserRouter>
<div>
<Switch>
<Route path="/edit/:id" component={EditExpensePage} />
</Switch>
</div>
</BrowserRouter>
);
};
ReactDOM.render(<AppRouter />, document.getElementById('appDiv'));
Error screenshot
I am trying to access the id in console as simple as that.
The error is showing only when I am trying to pass props
path="/edit/:id"
Source Link: https://reacttraining.com/react-router/web/api/Route/route-props
This is the same problem as in this question. The problem is specific to the setup. As shown in error message, bundle.js is loaded from current path, /edit/bundle.js, while it should be loaded from /bundle.js.
Scripts should either have absolute paths:
<script type="text/javascript" src="/bundle.js"></script>
Or base URL should be specified:
<base href="/">
It may be an issue with your local environment, I dont see anyproblem with your code. I tried out in https://codesandbox.io/s/ox773ywmn9 and there is no issue
I can access the props in the child components using this:
this.props.match.params.id

Images don't show only when optional html parameter is provided (but do show otherwise)

I have parent component that shows an image at a specified path (note: the image is already saved in my project). This path optionally can have additional parameters. If the
For example, The image is displayed (image) if the html path is:
www.mysite.com/myPath
The component is displayed but image is broken (broken image) if the html path is:
www.mysite.com/myPath/someFilterForThisPage
Router
// Libraries
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { browserHistory } from 'react-router';
// Components
import Home from './containers/Home';
import NotFound from './components/NotFound';
import MyComponent from './components/MyComponent';
// Redux
import { Provider } from 'react-redux';
import {createStore} from 'redux';
import allReducers from './reducers';
const store = createStore(
allReducers,
window.devToolsExtension && window.devToolsExtension()
);
// Routes
const routes = (
<Router history={browserHistory}>
<div>
<Provider store={store}>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/myPath/:filter?" component={MyComponent} />
<Route component={NotFound} />
</Switch>
</Provider>
</div>
</Router>
);
export default routes;
I don't think the issue is with my router.js file since the component still shows when a filter is applied in the html path (the image is just broken, ), but I am providing it just in case I am misunderstanding something.
My Component:
// React
import React from 'react';
class MyComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
<div>
<img src={"img/x.png"} id="someId" alt=""/> // ISSUE
// ...
// some divs that show/don't based on the filter of the html path
// ...
</div>
}
}
export default MyComponent;
I have looked at and tried some of the following, but with little luck:
React won't load local images
Dynamically Add Images React Webpack
I think these are different because these are mainly issues related to being unable to display images at all. I am able to display the image, but only when the optional html parameter is not set.
Does anyone know why the image is showing, but only if there is no extra html parameter?
Many thanks.
Any reason why {"img/x.png"} is not accessing root? Such as {"/img/x.png"} or setup your env domain as a global variable and add that in there otherwise you are looking inside every directory you hit for an img directory.

react-router-dom gives error

I have following implementation of "react-router-dom", but I am not able to get it working. can someone guide me what's the underlying issue.
App.jsx
import React from "react";
import Main from "../components/Main";
import Home from "../components/Home";
import { BrowserRouter, Match, Miss, Link } from 'react-router-dom';
const App = () => (
<BrowserRouter>
<div>
<Match exactly pattern="/" component={Main} />
<Match pattern="/home" component={Home} />
</div>
</BrowserRouter>
);
export default App;
Index.jsx
import React from "react";
import ReactDOM from "react-dom";
import Main from "./components/Main";
import Home from "./components/Home";
import Page from './components/Page';
import App from "./config/App";
ReactDOM.render(
<App/>,
document.getElementById('app')
);
I get the following error :
Please refer to the docs of React Router v4
Match and Miss are from previous versions of react-router-v4.alpha
With the current stable release of v4. You should use Route instead of Match. Miss is not there anymore.
I think this should solve your problem.
First of all, you should use Route instead of match.
Second, imports are case sensitive.
Third, match as per the doc you will get match object as prop.

reactjs - can not read property push of undefined

I have this code. What I want to do is when I click a button 'feature' it will take me to index route. However, React keeps saying 'can not read property push of undefined' What I've done wrong?
route.js
import React from "react";
import ReactDOM from "react-dom";
import {Router, Route, hashHistory, IndexRoute } from "react-router";
import Layout from "./page/Layout";
import Features from "./page/Features";
import Features from "./page/archive";
const app = document.getElementById('app');
ReactDOM.render(
<Router history={hashHistory}>
<Route path="/" component={Layout}>
<IndexRoute component={Features} />
<Route path="archive" component={Archive} />
</Route>
</Router>, app);
Layout component
import React from "react";
import {Link, Router, Route, hashHistory} from "react-router";
export default class Layout extends React.Component{
navigate(){
this.context.router.push('/');
}
render(){
return(
<div>
{this.props.children}
<button onClick={this.navigate.bind(this)}>feature</button>
</div>
)
}
}
package.json - partial
"react": "^0.14.7",
"react-dom": "^0.14.7",
"react-router": "^2.0.1"
"history": "^2.0.1",
-------------update to jordan's answer-------------
In React Router v4, you no longer have to give a history to your router. Instead you just use BrowserRouter or HashRouter from 'react-router-dom'. But that makes it unclear how to push a rout to your history when you aren't in a react component.
The solution is to use the history package.
Just import createHistory like this:
import createHistory from 'history/createBrowserHistory'
Or the way I do it is like this:
import { createHashHistory } from 'history'
then create your history
export const history = createHashHistory()
and now you can push to it:
history.push('/page')
I hope this helps others who come to this question. None of the current answers gave me what I needed.
This may not be referring to above example but I had the same error. After lot of debugging I figured out that history is not reachable to my inner components. Make sure your history is reachable.
//main.js
<BrowserRouter>
<div>
<Route path="/" component={Home}/>
<Route path="/techMap" component={TechMap}/>
</div>
</BrowserRouter>
//app.js
<div>
<TechStack history= {this.props.history}/>
</div>
//techstack.js
<div>
<span onClick={this.search.bind(this)}>
</span>
</div>
)
search(e){
this.props.history.push('/some_url');
}
TechStack is my inner component.
Earlier I was able to get history in app.js but not in tech.js.
But after passing props in form of history, I got the history in tech.js and routing works
With React router v4, you need to wrap the components in withRouter. Then you can access history in your components. Do the following:
import { withRouter } from 'react-router-dom';
...
...
export default withRouter(MyComponent);
You need to change your route.js page to
import {Router, browserHistory} from 'react-router';
ReactDOM.render(
<Router history={browserHistory}>
<Route path="/" component={Layout}>
<IndexRoute component={Features} />
<Route path="archive" component={Archive} />
</Route>
</Router>, app);
And then everywhere you want to navigate you can use
import {Router, browserHistory} from 'react-router';
browserHistory.push('/');
The react-router docs encourage you to use browserHistory instead of hashHistory
hashHistory uses URL hashes, along with a query key to keep track of
state. hashHistory requires no additional server configuration, but is
generally less preferred than browserHistory.
usually, when you are trying to redirect from a nested component it will give this error.
there are a few ways to fix it
Using react-dom you can import the withRouter component from react-router-dom then use it as usual with this.props.history.push and instead of the usual export default 'class' we will use export default withRouter(class); and boom problem solve.
I use browserHistory instead of HashHistory.
Then I just need to do the following:
import { browserHistory } from 'react-router'
// ...
// ...
navigate(){
browserHistory.push('/');
}
You don't need to use browserHistory anymore.
React-router-dom inject into your component route related props and context.
One of this props is 'history' and on this history object is a function push that you can call and pass the route you want to navigate to.
example in a Class base component, you can create a function like below as an onClick handler to redirect to specific link
redirectToPage() {
this.props.history.push('/page'); OR
this.context.router.history.push('/page');
}
while in a function base stateless component
redirectToSessionStatePage() {
props.history.push('/page');OR
context.router.history.push('/page');
}
Change your Layout component to have navigate assigned to ES6 lambda. This is needed to set the correct value of this
import React from "react";
import {Link, Router, Route, hashHistory} from "react-router";
export default class Layout extends React.Component{
navigate = () => {
this.context.router.push('/');
}
render(){
return(
<div>
{this.props.children}
<button onClick={this.navigate.bind(this)}>feature</button>
</div>
)
}
}
export default class Layout extends React.Component{
navigate = () => {
this.context.router.push('/');
}
render(){
return(
<div>
{this.props.children}
<button onClick={this.navigate.bind(this)}>feature</button>
</div>
)
}
}
Layout.contextTypes = {
router: PropTypes.object.isRequired
}
It looks like you overwrote your Features import with whatever is in your /archives directory. In the code you posted, you have this:
import Features from "./page/Features";
import Features from "./page/archive";
import {withRouter} from 'react-router-dom';
export default withRouter(AppName);

Categories