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.
Related
I have a project using react-router v6, and I am getting an error stating useNavigate() may be used only in the context of a <Router> component.
For some background, I have two projects that live in the same repo and get built together. We leverage code splitting and import them as needed, not sure if this matters.
Now, I have a setup that is pretty simple:
(in the #dummyInc/components project)
Dummy.tsx
import React from 'react'
export function Dummy() {
const navigate = useNavigate()
return <div> Hello World <button onClick={() => navigate('/someRoute')}> </div>
}
Then my code uses it in a different project that is just imported.
(in the #dummyInc/site project)
App.js
import React from 'react'
import Dummy from '#dummyInc/components'
export function App() {
return <div> <Dummy /> </div>
}
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import App from './src/App'
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
)
Now I have the above and when I try to render it in the browser, it says the following, but I'm not sure how that's possible, it's being rendered in that context.
Error: useNavigate() may be used only in the context of a <Router> component.
Am I missing something? Any help is appreciated.
I have the following ReactJS project structure and I'm getting the following error:
./src/index.js
Attempted import error: './components' does not contain a default export (imported as 'App').
My goal is to import components like this: import { App, Navbar } from 'components'; (notice the 'components') and not like ./components/App, ./components/App/index or so. To do that, I needed to add index.js in the components directory. I tried doing that by the following code, but I'm receiving the error above.
What's the reason? How do I solve it?
There are similar threads, but I'm already exporting it by export default App; in ./components/App/index.jsx. Maybe the reason is the .jsx extension?
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();
components/index.js
export App from './App';
components/App/index.jsx
import React, { Fragment } from 'react';
import './style.css';
import { BrowserRouter as Router, Switch, Route, Redirect } from 'react-router-dom';
import NotAuthorizedRoute from '../../common/NotAuthorizedRoute';
import { Navbar, Home, User, Login } from 'components';
const App = () => {
return (
<Fragment>
<Router>
<Navbar />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/users" component={User} />
<NotAuthorizedRoute path="/sign-in" component={Login} />
<Redirect from="*" to="/" />
</Switch>
</Router>
</Fragment>
);
};
export default App;
components/App/style.css
What I tried:
I tried doing the following, like people said in this thread: Attempted import error: 'App' is not exported from './App'.
components/index.js
export { App } from './App'; // note the brackets
But then I got:
./src/components/index.js
Attempted import error: 'App' is not exported from './App'.
It seems you are having some confusions with ES6 export/import syntaxes. MDN documentation is very explicative, I would recommend you to check it.
The most important thing is to remember the difference between default and named export/import. (HINT: When you see brackets in export/import statements you are dealing with named ones)
In your specific case, you will have to do as follows:
./components/component-a.jsx
const ComponentA = () => {
return (
<MyComponent/>
);
};
export {ComponentA};
./components/component-b.jsx
const ComponentB = () => {
return (
<MyComponent/>
);
};
export {ComponentB};
./components/index.js
import {componentA} from './component-a.jsx';
import {componentB} from './component-b.jsx';
export {componentA, componentB};
./some-file.jsx
import {componentA, componentB} from './components';
./some-other-file.jsx
import {componentA} from './components';
This is the typical pattern to create a virtual export/import namespace for logical module classification.
Please note that I've not used default exports. There are several opinions about this, but I would recommend to not use them to avoid errors like the one you are having.
Please also note that you'll always have to specify the full relative path to the components directory. The only way to import things from 'components' is by having a components package installed in your node_modules directory.
Make sure you are not using the exported value componentA in {componentA}
remove `{}` and check
I'm using material-react in my React project. We are using material-react in both shell and micro-frontend. The class names generated by both shell and micro-frontend are being same viz., .jss1, .jss2 which is causing style collisions.
Im trying to generate unique class names for the micro-frontend, something like App1-{className} using JssProvider classNamePrefix prop, but still the classnames are generating as it is (.jss1, .jss2 etc). I have installed react-jss#10.0.0 as of now. I have tried many solutions from stackoverflow and github issues as well. But none of them are working for me.
import React from "react";
import ReactDOM from "react-dom";
import { JssProvider } from "react-jss";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import App from "./components/App";
import "./styles.css";
import { Provider } from "react-redux";
const routing = (
<JssProvider classNamePrefix="App1">
<Provider>
<Router>
<Switch>
<Route exact path="/" component={App} />
</Switch>
</Router>
</Provider>
</JssProvider>
);
ReactDOM.render(routing, document.getElementById("root"));
Following is the css classes that are getting generated in prod environment.
I need something like App1-{className} for the class names, so that they don't clash with other styles with similar names.
I have followed these stackoverflow links, but unfortunately none of them are working for me.
React Admin displays very messed up
https://github.com/marmelab/react-admin/issues/1782
Please help me solve this thing. I feel i'm missing something very basic.
You could use the seed option of createGenerateClassName function which is part of #material-ui/core/styles:
options.seed (String [optional]): Defaults to ''. The string used to uniquely identify the generator. It can be used to avoid class name collisions when using multiple generators in the same document.
import React from "react";
import ReactDOM from "react-dom";
import { StylesProvider, createGenerateClassName } from '#material-ui/core/styles';
import { Provider } from "react-redux";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import App from "./components/App";
import "./styles.css";
const generateClassName = createGenerateClassName({
seed: 'App1',
});
export default function App() {
return (
<StylesProvider generateClassName={generateClassName}>
<Provider>
<Router>
<Switch>
<Route exact path="/" component={App} />
</Switch>
</Router>
</Provider>
</StylesProvider>
);
}
This part of the material-ui documenation solved my issue.
https://material-ui.com/styles/api/#creategenerateclassname-options-class-name-generator
Strangely the JSSProvider solution was not working for me, whereas it was working for others. For those who faced similar issue, can use StyleProvider instead of JSSProvider.
Have you tried to install same versions of material-ui in all of your libraries?
I had the same problem, I have different material ui versions in my app and in my custom component library. Installing the same version works for me.
React noob here, I'm trying to add a link in my material-ui toolbar using React-router v4 to the home page but I keep getting the error:
Element type is invalid: expected a string (for built-in components)
or a class/function (for composite components) but got: undefined. You
likely forgot to export your component from the file it's defined in.
Check the render method of LandingToolBar.
I'm trying to copy the basic example here https://reacttraining.com/react-router/web/example/basic but instead putting the top list in another component called LandingToolBar but I can't see to get it to work. Here is my index.js:
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import injectTapEventPlugin from 'react-tap-event-plugin'
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
injectTapEventPlugin();
ReactDOM.render(
<MuiThemeProvider>
<App />
</MuiThemeProvider>,
document.getElementById('app')
);
My app.js:
import React from 'react'
import {Route, BrowserRouter, Switch} from 'react-router-dom'
import LoginPage from "./containers/LoginPage";
import SignUpPage from "./containers/SignUpPage";
import HomePage from "./components/landing/HomePage";
import LandingToolBar from "./components/landing/LandingToolBar";
class App extends React.Component {
render() {
return (
<BrowserRouter>
<div>
<LandingToolBar/>
<Switch>
<Route path="/" exact component={HomePage}/>
<Route path="/login" component={LoginPage}/>
<Route path="/signup" component={SignUpPage}/>
</Switch>
</div>
</BrowserRouter>
)
}
}
export default App;
And the toolbar component LandingToolBar that I'm trying to render always:
import React from 'react';
import Link from 'react-router-dom';
import {ToolbarGroup, ToolbarTitle, RaisedButton, Toolbar} from 'material-ui'
const LandingToolBar = () => (
<Toolbar>
<ToolbarGroup>
<ToolbarTitle text="ETFly"/>
<Link to="/">feafeaf</Link>
</ToolbarGroup>
</Toolbar>
);
export default LandingToolBar;
Struggling pretty hard with the routing part as there doesn't seem to be much explanation in the docs or for v4 stuff...
Thanks for the help!
You need to import the Link like this, its a named import not default import:
import {Link} from 'react-router-dom';
Check this answer for named vs default import/export.
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);