Unable to pass props to component through react-router - javascript

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

Related

React router error "useRoutes() may be used only in the contect of a <Router> component."

So, I was making this website when I saw these BIG red errors in the console ( I know a nightmare :( )
The error said this:
Uncaught Error: useRoutes() may be used only in the context of a <Router> component.
And I didn't even use a "useRoutes" hook.
Anyways here's my code:
import Links from "./components/Links"
import Addition from "./pages/Addition"
import "./styles/App.css"
import { BrowserRouter as Router, Switch, Route, Routes } from 'react-router-dom';
function App() {
return (
<div>
<h1>Chose your operation:</h1>
<div className="cards">
<Routes>
<Route path="/addition" element={Addition} />
</Routes>
</div>
</div>
)
}
export default App;
The Routes component uses the useRoutes. Routes needs to be rendered within a routing context provided by a router component.
Additionally the Addition (sorry, no pun intended) needs to be passed to the element prop as JSX. This was one of the breaking changes in the Route component API from v5 to v6.
Example:
import Links from "./components/Links"
import Addition from "./pages/Addition"
import "./styles/App.css"
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
function App() {
return (
<Router> // <-- render app into Router component
<div>
<h1>Chose your operation:</h1>
<div className="cards">
<Routes>
<Route
path="/addition"
element={<Addition />} // <-- passed as JSX
/>
</Routes>
</div>
</div>
</Router>
)
}

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

React/Router/MemoryRouter - how to pass history property and use push() in child component?

I'm building a React app where I do NOT want the URL in the browser to be updated. I am NOT using 'react-router-dom' but only 'react-router' and MemoryRouter (https://reacttraining.com/react-router/web/api/MemoryRouter). The history.push() is available directly in the component statements but I wish to pass the history to children of children of these main components but the property is undefined.
Here is the Router section in main App.js (components Home and ScreeningTool can access this.props.history.push() as expected):
...
import {Route, MemoryRouter} from "react-router";
...
<MemoryRouter>
<Route exact path="/" component={Home} />
<Route path="/screening-tool" component={ScreeningTool} />
</MemoryRouter>
...
Both Home and ScreeningTool both use child component AppLink that generates a 'link' to navigate between Home and ScreeningTool like so (notice I'm passing 'history' as a prop):
Home.js:
...
<AppLink
url="/"
label="Screening Tool"
history={this.props.history}
/>
...
AppLink.js:
...
<div className="pseudo-link">
<span onClick={() => this.props.history.push(this.props.url)}>
{this.props.label}
</span>
</div>
...
The above code works. But there are children components in Home that will create their own AppLinks and also greatgrandchildren. I do NOT want to pass the history property as a component prop from Parent to Child to GrandChild components because this does not seem efficient. I have found the following stackoverflow questions but none of these options are working for me:
this.props.history.push works in some components and not others
react-router getting this.props.location in child components
I tried the newer 'userHistory' as described in the second URL above:
...
import { useHistory } from 'react-router';
...
render() {
let history = useHistory();
return (
<div className="pseudo-link">
<span onClick={() => history.push(this.props.url)}>
{this.props.label}
</span>
</div>
);
}
...
but I get Error: Invalid hook call. Hooks can only be called inside of the body of a function component..
I tried using withRouter as defined here https://reacttraining.com/react-router/web/api/withRouter but I get Error: Invariant failed: You should not use <withRouter(PseudoLink) /> outside a <Router>.
Finally, the accepted answer for this.props.history.push works in some components and not others ends with block of code export default withRouter(connect(mapStateToProps, matchDispatchToProps)(ChildView)); but does not explain where mapStateToProps or matchDispatchToProps comes from?
I'm thinking the issue is that I am using MemoryRouter and not normal/most common Router from 'reacto-router-dom'.
Can anyone help me out?
useHistory is a Hook so it should be used in a functional component, not inside a class based component.
Finally, the accepted answer for this.props.history.push works in some components and not others ends with block of code export default withRouter(connect(mapStateToProps, matchDispatchToProps)(ChildView)); but does not explain where mapStateToProps or matchDispatchToProps comes from?
-If you're not using redux then you can just use
export default withRouter(yourComponentName);
update
I've changed the AppLink component to this and it is working fine
import React from "react";
import "./AppLink.css";
import { useHistory } from 'react-router';
const AppLink = props => {
const history = useHistory();
return (
<div
className="app-link-button"
onClick={() => history.push(props.url)}
>
<span>{props.label}</span>
</div>
);
};
export default AppLink;

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 v4 - browserHistory is undefined

I am creating my first react app in electron (my first electron app too). I have two routes & need to navigate from one to another. For that I am using following code:
Root
ReactDOM.render(
<Router history={browserHistory}>
<App />
</Router>,
document.getElementById('root')
);
App
class App extends React.Component {
constructor() {
super();
}
render() {
return (
<div className="app-master">
<Switch>
<Route path='/city' component={CityList}/>
<Route path='/' component={SplashScreen}/>
</Switch>
</div>
)
}
}
Page
import { browserHistory } from 'react-router';
...
browserHistory.push('/city');
This line gives error,
TypeError: Cannot read property 'push' of undefined
I searched web for possible solution but can't find one! There are many similar questions on SO too, but none of it worked for me :(
You have to import it from the history module now which provides 3 different methods to create different histories.
createBrowserHistory is for use in modern web browsers that support the history API
createMemoryHistory is used as a reference implementation and may also be used in non-DOM environments, like React Native or tests
createHashHistory for legacy web browsers
You cannot use the browser history in an electron environment, use the hash or the memory one.
import { createHashHistory } from 'history'
const history = createHashHistory()
You can then use the history injected in the props
this.props.history.push('/')
Useful pointers above. The simplest solution I've found is to add:
import {createBrowserHistory} from 'history';
to your list of import statements, then add:
const browserHistory = createBrowserHistory();
Might not work perfectly, but for the basic stuff I'm working on seems to do the trick. Hope that helps.
Its is not working for your because in your component you are still using browserHistory which is not longer availabe from react-router package. You should change to using history from the history package
To simplify you can create a history.js file with the following contents
import { createBrowserHistory } from 'history'
export default createBrowserHistory();
Root
import history from '/path/to/history';
ReactDOM.render(
<Router history={history}>
<App />
</Router>,
document.getElementById('root')
);
Page
import history from 'path/to/history';
...
history.push('/city');
import { browserHistory } from 'react-router' does not work in React router 4. Link
Use the redirect component:
import { Redirect } from 'react-router';
<Redirect push to="/somewhere/else"/>
The render function should replace the entire content with Redirect component.
In react-router v4 initialize router as constant config and access the history through this.props in child components.
Import you dependecies
import { Route, Router } from "react-router";
import { createBrowserHistory } from "history";
Define your router config and add history as prop
const history = createBrowserHistory();
const routes = (
<Router history={history}>
<Route path='/city' component={CityList}/>
<Route path='/' component={SplashScreen}/>
</Router> )
class App extends Component {
render() {
return (
<div className = "app-master>
{routes}
</div>)
}
Defining route as a constant and out of render method this would initialize the route config only once.
Page Component
class Page extend Component {
render() {
this.props.history.push('/');
}
}
The history is now available as props in all the child components defined in routes config.

Categories