I've created a repository with a basic example that triggers this error in case it helps:
loadable-components-ssr
I'm trying to use Loadable Components in a SSR set up with react-router-dom 4.3.1, loadable-component 5.6.0 and react-dom 16.8.1
Here is a component example to which I'm trying to apply loadable-component:
import React from "react";
const About = () => <h2>About</h2>;
export default About;
This is imported in the App component like this:
import loadable from "#loadable/component";
...
const About = loadable(() => import("./About"));
And passed as a prop to Route in the same App component:
<Route path="/about/" component={About} />
But I keep getting the following warning in the Developer Tools console:
Warning: Failed prop type: Invalid prop component of type object supplied to Route, expected function
If I use an alternative syntax as suggested in the first answer:
<Route path="/about/" component={props => <About {...props} />} />
The warning disappears, but the route to /about still gives an error when the link is clicked:
Uncaught Error: Loading chunk About failed.
(missing: http://localhost:3000/about/About.bundle.js)
at HTMLScriptElement.onScriptComplete (VM1805 app.bundle.js:114)
I followed the documentation about setting up loadable-components in SSR, so I've set up the client, the server and also the babel plugin as indicated.
Any idea what's wrong here?
This is a known issue of react router.
I think that you could code the route like this:
<Route path="/about/" component={props => <About {...props} />} />
Be careful with this implementation, because you could have some buggy behaviours with the re-renders.
this is your "About" component:
import React from "react";
const About = () => <h2>About</h2>;
export default About;
you are not returning jsx. thats why you are getting error.
this is how you should have returned jsx.
const About = () => (<h2>About</h2>);
cheers!
why don't you use react.lazy? It is the official component.
const About = React.lazy(() => import('./About')
<Route exact path="/about" component={props => <About {...props} />} />
Related
I've a condition where I've 3 components
A.js B.js C.js
In old code
routes.js
const A = lazy(() => import("../test/A"));
const B = lazy(() => import("../test/B"));
const C = lazy(() => import("../test/C"));
<Route
path="/test"
render={({ match: { url } }) => (
<Switch>
<Route exact path={`${url}/a-test`} component={A} />
<Route exact path={`${url}/b-test`} component={B} />
<Route exact path={`${url}/c-test`} component={C} />
</Switch>
)}
/>
What I want to achieve
By the above code we can conclude that every time the separate builds
for A, B, C will get download due to lazy load, but I want to achieve
a functionality where I can download all 3 of them altogether, i.e.
When a download a single component using that only I can download all
three of them as a single separate build
What I tried - New Code
combine_module.js
import A from "./A";
import B from "./B";
import C from "./C";
const test = {A, B, C};
export default test;
routes.js
const Test = lazy(() => import("../test/combine_module"));
<Route
path="/test"
render={({ match: { url } }) => (
<Switch>
<Route exact path={`${url}/a-test`} component={Test.A} />
<Route exact path={`${url}/b-test`} component={Test.B} />
<Route exact path={`${url}/c-test`} component={Test.C} />
</Switch>
)}
/>
Code
Full code link
My Issue
I don't know about the approach whether it's wrong or right as I'm not getting any error or any warning related to this in the console but seeing a blank screen cannot see the output, So can please anybody tell how to make this thing right and achieve the desired functionality.
According to the React.lazy documentation:
React.lazy takes a function that must call a dynamic import(). This must return a Promise which resolves to a module with a default export containing a React component.
So the result of React.lazy is not a module but a special object Suspense can work with.
A usual module can be loaded lazily with WebPack's dynamic import. There is a tricky part with this because the module can be loaded after the component was rendered. So two things we need to do:
1) ensure the component does not render undefined while module is being loaded
2) update the component when the module has been loaded
Updating is quite simple we can make a hook that will set the module as state on load
function useDynamicModule(path) {
const [module, setModule] = useState({});
const [error, setError] = useState();
useEffect(() => {
import(path).then(setModule, setError);
}, []);
return error ? { $error: error } : module.default
}
Usage:
export default function App() {
const Test = useDynamicModule("./CombineModule");
if (!Test) return null;
if (Test.$error) return "Error";
return (
<Router history={history}>
// ...
</Router>
);
}
Playground
I'm creating my first app with react-router and was having some trouble with an invalid hook error. I did manage to fix the error, but I don't really understand why this fixed it. So, in my App component I had a Switch with the following Route:
<Route
path="/signin"
exact
render={SignIn}
/>
Now lets suppose the SignIn component looked like this:
import React, { useState } from 'react';
const SignIn = () => {
const [test, setTest] = useState('test');
return (
<main>
{test}
</main>
)
}
export default SignIn;
With this set-up I kept getting an invalid hooks error, which only went away when I changed the Route in the App component to this:
<Route
path="/signin"
exact
render={(props) => <SignIn {...props}/>}
/>
Now this had solved the problem and the invalid hook problem went away, but why? I am not actually using any props in the SingIn component, at least not at the moment. Which of the React Hook Rules am I breaking here?
Since SignIn is a component, you can do it like this:
<Route
path="/signin"
exact
component={SignIn}
/>
The render syntax is when you want to pass some additional props
I am working on existing code base for a react application. I am new to React and the developer who wrote this left.
In my current code base "request-promise-native" is pass from one component to another component using props. I don't get this. Why not just import it again in every component?
App.tsx
import rp from 'request-promise-native';
const App: React.FC = () => {
return (
<Router>
<Route path="/" render={(props) => <Main {...props} rp={rp} />}></Route>
</Router>
)
};
After reading the documentation of https://www.npmjs.com/package/request-promise it appears this is completely pointless and you are correct about imports.
this is my first post in Stackoverflow and I hope you guys can give me some guidance.
I'm currently learning React Router and it seems that I got stucked on an error or bug that I can't find to solve. To give you a little overview about the setup, here it is:
I'm using CRA with React-Router-DOM 5.0.1.
I'm using React Hooks to practice and using latest version of React 16.8.6
This is an app that reads a local API and it renders its data on different components. Here is the code:
App.js
import React, { Fragment, useState, useEffect } from 'react';
import { BrowserRouter, Link, Route, Switch } from 'react-router-dom';
import axios from 'axios';
import Writers from './Writers';
function App() {
const [writers, setWriters] = useState([]);
useEffect(() => {
const fetchData = async () => {
const result = await axios('http://localhost:3004/writers');
setWriters(result.data);
};
fetchData();
}, []);
return (
<BrowserRouter>
<Fragment>
<ul>
<li>
<Link to='/'>Home</Link>
</li>
<li>
<Link to='/writers'>Writers</Link>
</li>
</ul>
<Switch>
<Route exact path='/' render={() => <div>Home</div>} />
<Route
exact
path='/writers'
render={props => <Writers {...props} writers={writers} />}
/>
</Switch>
</Fragment>
</BrowserRouter>
);
}
export default App;
Writers.js
import React, { Fragment } from 'react';
import { Route, Link } from 'react-router-dom';
import Writer from './Writer/index';
const Writers = props => {
console.log(props);
return (
<Fragment>
<ul>
{props.writers.map(({ id, name }) => (
<li key={id}>
<Link to={`${props.match.url}/${id}`}>{name}</Link>
</li>
))}
</ul>
<Route
path={`${props.match.url}/:writerID`}
render={props => <Writer {...props} />}
/>
</Fragment>
);
};
export default Writers;
Writer.js
import React, { Fragment } from 'react';
const Writer = ({ match, id, name, description }) => {
console.log(match);
return <Fragment>id name description</Fragment>;
};
export default Writer;
So I'm having an issue in Writers.js where I'm passing the params "/:writerID", this params doesn't get to Writer component and actually Writer component never gets rendered at all
<Route
path={`${props.match.url}/:writerID`}
render={props => <Writer {...props} />}
/>
If I remove :writerID from the path prop, the component Writer gets rendered BUT it doesn't allow me route it the unique path that I'm looking for.
Any idea why this might be happening? Any help will be greatly appreciated.
I have tried making sure I have the correct exports on my files and they are, in fact, I don't see any errors from the CRA logs.
Also, I remove the params from the path props and it seems that the Writer components renders but if I put it again, it doesn't work.
App.js passing Writers with props and writers data
<Route
exact
path='/writers'
render={props => <Writers {...props} writers={writers} />}
/>
Writers.js receives the data and Route props so I can access Match props but this component does NOT render Writer component neither get the match.params prop.
<Route
path={`${props.match.url}/:writerID`}
render={props => <Writer {...props} />}
/>
Expected behavior: Writer.js should be render when trying to click on any individual writer and it should allow me to get the match.params prop.
Actual Behavior: Writer.js does not gets rendered and if I remove the path prop from Route, it gets render but I can't access the individual id.
In your Route path for /writers you are using the exact prop, which will lead to any nested Route not being rendered. Remove the exact prop and your Routes will work
<Route
exact
path='/writers'
render={props => <Writers {...props} writers={writers} />}
/>
Also as a thumb rule you should use match.url for Link path and match.path for a Route path
I'm using the latest version (16.6) of React with react-router (4.3.1) and trying to use code splitting using React.Suspense.
Although my routing is working and the code did split into several bundles loaded dynamically, I'm getting a warning about not returning a function, but an object to Route. My code:
import React, { lazy, Suspense } from 'react';
import { Switch, Route, withRouter } from 'react-router-dom';
import Loading from 'common/Loading';
const Prime = lazy(() => import('modules/Prime'));
const Demo = lazy(() => import('modules/Demo'));
const App = () => (
<Suspense fallback={<Loading>Loading...</Loading>}>
<Switch>
<Route path="/" component={Prime} exact />
<Route path="/demo" component={Demo} />
</Switch>
</Suspense>
);
export default withRouter(App);
The console warning is as follows:
Warning: Failed prop type: Invalid prop `component` of type `object` supplied to `Route`, expected `function`.
A normal import would return a function, but the dynamic import with lazy() is returning an object.
Any fixes for this?
Try using render prop instead of component
<Route path="/" render={()=> <Prime />} exact />
<Route path="/demo" render={()=> <Demo />} />
This will be fixed in react-router-dom version 4.4+ as this issue suggests
You can wait for the final release or if you don't want to change your code today,
you can install the beta version now by yarn add react-router-dom#next
I know this answer do not respond the original question, but as I have experienced a similar issue, maybe my solution will help another people.
My Error:
Failed prop type: Invalid prop `component` of type `object` supplied to "link", expected function.
Alike the accepted answer, this could be fixed with:
<Link to={'/admin'} title={'Log In'} component={props => <Button {...props} />} />