React-router-dom goBack(), how to inherit prop from another js file? - javascript

My route path is in separated file that contains only routes, nothing more and this is the only file that I'm importing in it React-router-dom.
The thing is, I want to specify a button in another js file, that will do goBack() function but I don't want to import react-router-dom here, but inherit prop from the main js file.
So, I have added to my App.js this lines (this is the main file that only have routes)
constructor(props) {
super(props);
this.goBack=this.goBack.bind(this);
}
goBack(){
this.props.history.goBack();
}
And the button
<button onClick={this.goBack}>Go Back</button>
Is there a way to do it that way or I really need to import router-dom and add constructor to another file?

You don't need to import router-dom on your new file. You just need to pass down the history prop all the way to the button component. Alternatively, set the history prop in a context or redux store variable - hopefully your back button is not nested deep in your component tree. Tip: Try to have your component using router props shallow in your tree to avoid passing through router props.
My router is set up something like:
<Router>
<div>
<Switch>
<Public exact path="/" component={ConnectedLoginForm} {...props} />
<Route path="/recover-password" component={ConnectedRecoverPasswordForm} />
<Route path="/reset-password/:token" component={ConnectedResetPasswordForm} />
<Route path="/invite/:token" component={ConnectedAcceptInviteForm} />
<Public path="/login" component={ConnectedLoginForm} {...props} />
<Authenticated path="/:co_id" component={ConnectedMainView} {...props} />
</Switch>
</div>
</Router>
Thus I have access to history prop in my ConnectedMainView component.

Related

Using Router DOM with React.js TypeError: Cannot read property "name" of undefined

I am trying to implement the React Router on my React.js application but as soon as I added the Router to my program I started getting a weird error.
ReactDOM.render(
<BrowserRouter>
<App />
<Route path="/" component={Headline}></Route>
<Route path="/economy" component={Economics}></Route>
</BrowserRouter>,
This is where I am implementing my <Router> component in index.js. But for some reason as soon as I add this to my application, I get the error:
TypeError: Cannot read property 'name' of undefined
name is the parameter of one of my objects, userInput, that I am passing via props to my child component, "headline" from App.js
<Headline
userInput={this.state.userInput}
money={this.state.money}
displayFakeNews={this.state.displayFakeNews}
onPublish={this.handlePublish}
/>
Inside the headline.jsx file, I am calling a <button> tag with the text rendering {this.props.userInput.name} and it the error comes up.
As soon as I remove the <Router> component from the index.js file, everything starts working absolutely perfectly.
*Note - Yes I tried to put the <Router> component in my App.js as well. And no I did not forget to import it.
In your routes, you're declaring that the component to be rendered at route "/" is the Headline component, but you're not passing it any props. This means that whenever you visit the home page, the Headline component is likely trying to access unassigned properties.
From your question, I assume that you already have the Headline component being rendered in your <App /> component, and in this file, it is actually being passed the necessary props. If its already being rendered there, you don't need to use the <Route /> outside of the <App />. It's not clear the functionality you're looking for or how you've written your <App /> component, but I think what you should keep in mind is that the syntax you're using doesn't pass any props to <Headline /> from the route. If you actually want to pass those props, change
<Route path="/" component={Headline}></Route>
to
<Route path="/">
<Headline
userInput={this.state.userInput}
money={this.state.money}
displayFakeNews={this.state.displayFakeNews}
onPublish={this.handlePublish}
/>
</Route>
Passing the component to be rendered as a child of the route, so that you can actually pass it props.
Consult the React Router documentation for more information on how to use the <Route /> component.

reactjs props getting lost in Route creation

I'm attempting to pass a user's auth state down to components via a react-router-dom switch block (I believe I ought to look at implementing redux but that's a question for later).
There's a Home view that gets passed all the login information after the user authenticates, and I can see the authState object as a prop in the home component using react devtools:
import React from "react";
import Dashboard from "../Dashboard";
import {Switch, Route} from "react-router-dom";
import NoMatch from "../NoMatch";
function Home(props) {
// authState exists
return (
<Switch {...props}>
// authState exists
<Route exact path="/" render={(...props) => <Dashboard {...props} />} /> // authState gone
<Route component={NoMatch} />
</Switch>
);
}
export default Home;
after executing this it renders the Dashboard, and tracing down the component chain with react devtools I can see that the prop has been passed from the Home component to the Switch component successfully. However, once it gets to the Route the prop is gone, and the only props available in the Dashboard component are the history, location and match props.
Why are the props missing and what's the right way to pass them down?
Couple of improvements needed in your code:
Passing props to Switch component is unnecessary
No need to collect router props using the rest syntax only to spread them later
Main Problem:
props inside the function passed to render prop refers to the router props instead of the props passed to Home component. You are using the same identifier for two different things.
Solution
Use different names for router props and the props passed to Home component that you want to pass down to Dashboard component
function Home(props) {
return (
<Switch>
<Route
exact
path="/"
render={(routerProps) => <Dashboard {...routerProps} {...props} />}
/>
<Route component={NoMatch} />
</Switch>
);
}
Alternatively, if you don't need access to router props in the Dashboard component, remove the props parameter from the render prop function.
<Route
exact
path="/"
render={() => <Dashboard {...props} />}
/>
Now, you won't have access to router props inside the Dashboard component but the auth state of the user will be passed down to Dashboard component.
In the most recent versions of the react-router-dom you must replace render and component attributes with element. You cannot pass a callback function there in which there were specified the route props anymore.
Instead you can use a hook in your routed component:
const params = useParams();
to obtain the parameters.
See more in the official documentation.

React - TypeError: Cannot read property 'push' of undefined, already exported default withRouter

I have a page component SimulationReport that I want to redirect to upon clicking a button from the Reports page component. This is the App component with the Router:
function App() {
return (
<React.Fragment>
<Router>
<NavigationBar />
<Sidebar />
<Switch>
<Route exact path="/" component={Ratings} />
<Route path="/LeagueSettings" component={LeagueSettings} />
<Route path="/Fixtures" component={Fixtures} />
<Route path="/Reports" component={Reports} />
<Route path="/SimulationReport" component={SimulationReport} />
</Switch>
</Router>
</React.Fragment>
);
}
And here are the relevant code bits from Reports which is a function component:
import {withRouter} from "react-router-dom";
<td>
<Button variant="primary" onClick={handleSimView(index)}>
View
</Button>
</td>
const handleSimView = index => e => {
console.log("index: " + index);
loadSimulationResult(simulationIds[index]);
props.history.push("/SimulationReport");
};
And at the end of the file I have this:
export default withRouter(Reports);
Upon clicking the button, I receive this error:
TypeError: Cannot read property 'push' of undefined
I'm not sure what I need to do to redirect this? Or maybe I should be doing it a different way?
Seems that your prop history is not being passed from the <Route> tag in your component.
You can pass props to a Route Rendered Component by doing the following line:
<Route
path='/SimulationReport'
render={(props) => <SimulationReport {...props} history={yourHistoryObjectForTheRouter} />}
/>
where yourHistoryObjectForTheRouter would be your custom history exported object.
EDIT: Updated code
UPDATE TO ANSWER TO ADDRESS OP's NEEDS:
1° Alright, so first you'll need to install the package called history to your React Application. (You can use npm i history or yarn add history. It depends on what you have installed. If you don't know what's yarn then use the npm option)
2° Somewhere in your project inside the App folder (src/App/), you're going to create another folder called history and inside index.js.
The contents of the index.js file are going to be the next ones.
import { createBrowserHistory } from 'history';
export default createBrowserHistory({});
3° Once that is done, head to your App/index.js file, where you have your <Router> main tag. If you've done everything as I stated before, in that App/index.js you're going to add a new import:
import history from "./history";
Which is your new Custom History Object.
Here you can choose two paths of how you want to solve your problem
=== First Solution
4° Scroll down in that same file, until you find your <Router></Router> tag, and you're going to update it to this next part:
<Router>
<NavigationBar />
<Sidebar />
<Switch>
<Route exact path="/" component={Ratings} />
<Route path="/LeagueSettings" component={LeagueSettings} />
<Route path="/Fixtures" component={Fixtures} />
<Route path="/Reports" component={Reports} />
<Route
path='/SimulationReport'
render={(props) => <SimulationReport {...props} history=
{history} />}
/>
</Switch>
</Router>
After this, you'll have your Custom History Object setted up and your component now should work.
This solution however will only work for that specific component Route, and that means that you will have to do the same for the other <Route > that require the use of the history object.
Stop here if you choose this solution.
=== Second Solution
This solution is better, because you'll now have access to your history object globally, just with an import.
4° Scroll down in that same file, until you find your <Router></Router> tag, and you're going to update it to this next part:
<Router history={history}> //Here's the change
<NavigationBar />
<Sidebar />
<Switch>
<Route exact path="/" component={Ratings} />
<Route path="/LeagueSettings" component={LeagueSettings} />
<Route path="/Fixtures" component={Fixtures} />
<Route path="/Reports" component={Reports} />
<Route path="/SimulationReport" component={SimulationReport} />
</Switch>
</Router>
After this, you'll have your Custom History Object setted up.
5° Navigate to the file that contains the Reports functional component, and on the imports at the top of your file, you're going to import the same history as you did in App/index.js. Beware that depending on the level of subfolders that your Reports components is in, it's how the import is going to change. It can end up like this:
import history from "../history";
or this
import history from "../../history";
it depends or even more "../". It depends on your subfolder levels
After that, you'll need to update your function handleSimView so instead of doing this:
const handleSimView = index => e => {
console.log("index: " + index);
loadSimulationResult(simulationIds[index]);
props.history.push("/SimulationReport");
};
do this:
const handleSimView = index => e => {
console.log("index: " + index);
loadSimulationResult(simulationIds[index]);
history.push("/SimulationReport"); //Change is here, removed "props."
};
After this, your code should work. This solution you can implement it everywhere as you would only need to import the history object and just use it.
I'll be waiting to hear from you to see if it worked. If anything else happens, you can ask me.

How do I create `/orders/:id/detail` path in react-router

I would like to create a path /orders/{order_id}/detail using react-router. How do I do this on the <Route /> component and also when using the <Link /> to navigate to the path.
Currently I have it like this
<Route exact path='/orders/:id' component={OrderDetails} />
but I want it like this
<Route exact path='/orders/:id/detail' component={OrderDetails} />
Any help appreciated.
this route:
<Route exact path='/orders/:id/detail' component={OrderDetails} />
is correct, its going to render the OrderDetails component on this uri:
/orders/whatEverId/details
the point is the navigation to this url to render that component, for that you need to know that every component that rendered with react router directly has three extra props, location, match and history, and you can get them from this.props automatically if you are using class based components, if you are using function component you need to use their hook called useParams hook that react-router provides and ddestructure the parameter that you want from url.
more info is here

Passing props to props.children, receiving wrong props

App.js is the wrapper for my page, it's the layout enclosing the routes. Initially my routes were in App.js, but I want them in a higher order component so I can create routes which arent wrapped by App.
This is my current setup:
index.js
ReactDom.render(
<Provider>
<BrowserRouter>
<Route path='/' [...] /> // <-- Component which is NOT wrapped in App
<App>
<Route path='/about' component={About} /> // <-- I want About to receive the props from App
</App>
</BrowserRouter>
</Provider>
);
My App.js holds the Header, Sidebar and Footer component. App.js is the component I am exporting with connect(), I am mapping my redux state and actions with mapStateToProps and mapDispatchToPros in App.js
To pass the props down to, say, About, I tried different things with the same result, one of them being:
App.js
{React.cloneElement(this.props.children, {...this.props})}
However, the props I receive in About are completely different from the ones I am passing down. They are like this: (json)
{"match": {"path":"/about", "url": "/about", "isExact":true [...]}
So I am guessing those props come from the index.js, where my routes are. But how do I achieve what I am trying to do? Index.js is the component I am rendering the whole Application in. I am not exporting index.js.
Should I move the redux related stuff like mapStateToProps, mapDispatchToProps, connect(), ... to index.js? Or is there another solution?
Thanks!

Categories

Resources