I saw that using <React component> and <React render>, may be deprecated in react-router-dom 6.x, so i followed the migration steps of removing the component property, and instead nesting the component as a child of the <Route > node. it worked fine until i got to my routes that use dynamic parameters, and it threw an error.
i changed from...
<Route exact path={`/:category`} component={CategoryPage} />
to...
<Route exact path={`/:category`}>
<CategoryPage />
</Route>
the error is
Exception has occurred: TypeError: Cannot read property 'params' of undefined
at selectParams
it seems pretty straightforward, so is there anything else i need to look at that might be causing this?
UPDATE
i am using useParams in my categoryPage, which works fine while using <React component>
const CategoryPage = () => {
const { category } = useParams()
...
When you make use of children or elements props as specified in react-router v6, the components rendered are not passed the router props directly so you have to make use of useParams, useNavigate, useLocation or useRouteMatch hooks depending on your useCase in the child component if you child component is a functional component
If you child component is a class component, you will make use of withRouter HOC
For your case useParams hook is required to get access to the category param
Please check out this migration guide from v5 to v6 for more details
Related
Hi i'm currently upgrading react-router-dom from 5.2.0 to 6.3.0 for my react typescript application. while converting the application I'm getting this error Module '"react-router-dom"' has no exported member 'match'.
here you can find the below code.
import { match } from 'react-router-dom';
export interface ContentTypeIdParams {
contentTypeId: string;
}
export interface ContentTypeBreadcrumbProps {
match: match<ContentTypeIdParams>;
}
I'm facing this error in my interface.
my route path
<Route
path={`${RoutesEnum.RELEVANCE_TESTING_VERSIONS_COMPARISON_TEST_CASE}*`}
element={({ match: { params } }) => (
<Redirect
to={getUrlWithParams(
RoutesEnum.RELEVANCE_TESTING_VERSIONS_COMPARISON,
params
)}
/>
I searched a lot about this error but couldn't find any answers or questions.
if anyone knows about this kindly answer this.
It seems you are just wanting to "sniff" the route's params object to pass to a path generating utility function. The Route component takes only a ReactNode, a.k.a. JSX on the single element prop. There are also no longer any route props, replaced by React hooks.
Create a component that accesses the route path params via the useParams hook and renders a declarative redirect.
I'm not sure what RoutesEnum.RELEVANCE_TESTING_VERSIONS_COMPARISON is so passing it in as a prop to Redirect. It's not something being mapped over then it might be something that is just imported and used, and in this case the paramArg isn't necessary.
Example:
import { Navigate, useParams } from 'react-router-dom';
const Redirect = ({ paramArg }) => {
const params = useParams();
return <Navigate to={getUrlWithParams(paramArg, params)} replace />;
};
export default Redirect;
...
import Redirect from '../path/to/Redirect';
...
<Route
path={`${RoutesEnum.RELEVANCE_TESTING_VERSIONS_COMPARISON_TEST_CASE}*`}
element={<Redirect paramArg={RoutesEnum.RELEVANCE_TESTING_VERSIONS_COMPARISON} />}
/>
I know that the Router component, say BrowserRouter creates a history object for keeping track of paths and so on, and that a Route component renders its view only when its path matches the current location, which I assume is read from the history. My question is how does the Route component get access to the history object that is created by the BrowserRouter. Is there some under the hood communication going on that is making this possible?
This is a context api 'magic'.
<BrowserRouter/> renders <Router/>:
class BrowserRouter extends React.Component {
history = createHistory(this.props);
render() {
return <Router history={this.history} children={this.props.children} />;
}
}
<Router/> renders <RouterContext.Provider/>:
<RouterContext.Provider
children={this.props.children || null}
value={{
history: this.props.history,
<Route/> uses <RouterContext.Consumer> to provide access to data from provider.
Using context api allows to provide data/methods many levels down the tree without the need of passing down props expliticely (on each level). You can read more about this on docs or search for tutorials.
I am new using react router v4. I have a link that runs a function in the onClick event and then redirects to a specific route.
This is the link:
<Link className={''}
to={'/test'}
onClick={this.testFunction}>To test</Link>
and the test function:
testFunction(event){
e.preventDefault();
// do some things...
this.props.history.push('/test');
}
This works but I need to write both times the "/test" route (in the Link component and in the function).
Is there a way of getting the "to" prop so I don't have to write it twice?
If you use "withRouter" in your component:
import {Link, withRouter} from 'react-router-dom';
...
export default withRouter(TestComponent);
you can access the route's path by using:
this.props.match.path
Use this in your code:
testFunction(event){
e.preventDefault();
// do some things...
this.props.history.push(this.props.match.path);
}
When you use "withRouter" in your component you can access the match, location and history props of the route.
withRouter official documentation
match official documentation
Hope it helps!
Cannot seem to find much quality documentation on this. React Router v4 documentation has information of the 'history' object but states that it is mutable and should not be changed. Many examples I have seen seem like 'hacks'. Any insight would be appreciated.
I had to grapple with this one for a while as a react newbie myself. While the link that #ToddChaffee provided gives you a good insight, this thread highlights that the history object is automatically passed as a prop when you have <Router/> as the top level component. That makes it much simpler than loading the history object separately and using the createBrowserHistory() method.
The following worked for me:
<Route exact path='/' render={({history}) =>
<Home infoHandler={this.handleUserInfo}
imageHandler={this.handleImage}
history={history}/>
}/>
Then inside the component you can:
this.props.history.push('/routeYouWantToGoTo');
Don't forget to typecheck the prop in you component before you export the module:
Home.propTypes = {
history: React.PropTypes.object
}
export default Home;
For example I have routes like:
<Route path="about" component={AboutPage} />
<Route path="status" component={StatusPage} />
Lets assume that the current route is '#/about'. I need something like routerInstance.currentComponent to return AboutPage component instance.
Does React Router has a method to do it?
ps. I understand that accessing component instances from the outside is not the React Way to do things, but nevertheless I need it.
not sure if react-router already exposes it, theres an old GitHub discussing undocumented api's, here but you could set it yourself per Route.
//AboutPage
componentDidMount() {
global.currentComponent = this
}
//StatusPage
componentDidMount() {
global.currentComponent = this
}