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

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} />} />

Related

nested routing isn't working with react-router

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 '/'

Creating dynamic Link with some text before it

I was building a search engine for custom project.
There I have a search bar from where user can search.
When the user searches, I want the given link to work as it works in case of google
www.google.com/ search? queryRelatedInfo
Notice the search? and then whatever query/parameter/ID
for this I tried something like this in
import React, {Component} from 'react';
import {
BrowserRouter,
Route,
Switch,
Redirect,
} from 'react-router-dom';
import SearchScreen from "./container/searchScreen.js"
import HomeScreen from "./container/home.js";
class route extends Component {
render () {
return (
<BrowserRouter>
<div>
<Switch>
<Route path ="/" exact render ={(props) => <HomeScreen {...props}/>} />
<Route path ="/search?:id" exact render ={(props) => <SearchScreen {...props}/>} />
</Switch>
</div>
</BrowserRouter>
)
}
}
export default route
Notice, <Route path ="/search?:id" above.
Unfortunately this didn't worked out.
I understand that <Route path ="/:id" works but how can i make <Route path ="/search?:id to work i.e how can I make some link like http://localhost:3000/search?9e9e to work
I think this is related with historyApiFallback. That parameter;
(https://webpack.js.org/configuration/dev-server/#devserver-historyapifallback)
When using the HTML5 History API, the index.html page will likely have to be served in place of any 404 responses. devServer.historyApiFallback is disabled by default. Enable it by passing:
module.exports = {
//...
devServer: {
historyApiFallback: true
}
};
Your react app is a single page application. So all path except home path actually is an virtual path, they are not physically exist. The paths must routed to home path. So react-router can manage.
you don't need to put the path like this /search?:id, just put it search
<Route path ="/search" exact render ={(props) => <SearchScreen {...props}/>} />
then inside your SearchScreen component, get the value of search parameter from the URL, check this issue will help.
after the user make search, pass the value like this /search?s=value_here

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

Browser Router from React-Dom not working

I am attempting to serve a react app from the public folder of my rails app. I am building the js file and putting it in the public folder. When I go to the root of the app, I can see that the js and my index.html page have loaded. However, when I try to go to page, like /landing, I get a 404, route not found from Rails. I can't figure out why the react router is not kicking in. This all works on dev where I am serving the react app with a second server, I only get this issue in production. Any suggestions?
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.scss';
ReactDOM.render(<App />, document.getElementById('root'));
App.js
import React from 'react';
import Auth from './util/auth';
import { Redirect, BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import MyAccount from './components/my_account';
import MyListings from './components/my_listings';
import LoginPage from './components/login_page';
import LandingPage from './components/landing_page';
import RegistrationForm from './components/registration_form';
import PasswordResetForm from './components/password_reset_form';
import RequestPasswordResetForm from './components/request_password_reset_form';
import {FlashMessages} from './components/flash_messages';
import $ from 'jquery';
import popper from 'popper.js';
import './stylesheets/App.css';
window.Popper = popper;
window.jQuery = $;
window.$ = $;
global.jQuery = $;
require('bootstrap');
const App = appProps => (
<div>
<div id="flash-messages">
<FlashMessages />
</div>
<Router>
<div className="App">
<Switch>
<Route exact name="index" path="/landing" component={LandingPage} />
<Route exact name="login" path="/login" component={LoginPage} />
<Route exact name="register" path="/register" component={RegistrationForm} />
<Route exact name="reset_password" path="/reset_password" component={PasswordResetForm} />
<Route exact name="reset_password_request" path="/reset_password_request" component={RequestPasswordResetForm} />
<PrivateRoute path="/my_account" component={MyAccount}/>
<PrivateRoute path="/my_listings" component={MyListings}/>
</Switch>
</div>
</Router>
</div>
);
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props => (
Auth.isAuthenticated() ? (
<Component {...props}/>
) : (
<Redirect to={{
pathname: '/login',
state: { from: props.location }
}}/>
)
)}/>
)
export default App;
A typical gotcha with React Router is that you need to return the same index.html page for all routes - be it /, /landing-page/ or /a/really/deep/route/.
You typically solve that by adding a catch-all route. I don't know rails all that well, but I think this answer might help you out.
The problem is that all routes handled first by rails and he redirects you to the page where your react routers are. And you have only one HTML page that contains your react.js code.
When you go to /login or any other page you get err 404 because you don't have a route in rails to handle it.
You need to add rails routes for all your pages and redirect them to the same index page
Or do a catch all routes to the same index page
There's some documentation for configuring your server. Basically you always need to return index.html with a 200 status code.
https://github.com/ReactTraining/react-router/blob/v3/docs/guides/Histories.md#configuring-your-server

Cannot find module with async component loading on react router

I have the following basic starting point to load a component via import().
function getComponentAsync(importPath: string) {
return async (nextState, callback) => {
const { default: Component } = await import(importPath);
callback(null, Component);
}
}
export default (
<Route path="/" component={App}>
<IndexRoute getComponent={getComponentAsync('app/components/Home')} />
</Route>
);
The goal is to simply load a component at some path. However, I keep running into some errors:
I placed a debug statement to confirm that the import path was correctly passed down to the function. It appears to be.
However, I really can't find what it is trying to import nor why it is failing to import it... why would this be? I've also tried swapping out import for require.ensure and got the same results.

Categories