ReactJs Router Duplicates itself when wrap it in component - reactjs

I'm beginner in react, I'm using React 4, Redux and react-router-dom package for my router.
I have an App.js file which connects Main with mapStateToProps & mapDispatchToProps
//App.js
const App = connect(mapStateToProps, mapDispatchToProps)(Main);
My Main component renders a header and clones child elements
//Main.js
export default class Main extends React.Component {
render() {
return (
<div>
<h1>Hi I'm Header</h1>
{React.cloneElement(this.props.children, this.props)}
</div>
);
}
}
My child components contains a simple Json stringify of props
//UserList.js
export default class UsersList extends React.Component {
render(){
return (
<pre>
{JSON.stringify(this.props, null, "")}
</pre>
);
}
}
I made an index.js file which has a route and contains provider, and provider child is a router and my router contains other app routes
//index.js
const router = (
<Provider store={store}>
<App>
<Router history={history}>
<Switch>
<Route exact path="/" component={UsersList}/>
</Switch>
</Router>
</App>
</Provider>
);
render(router, document.getElementById('root'));
As you see I have an App, my app connects main to mapstatetoprops and mapdispatchtoprops, and finally gives the child route (UsersList component) to the parent (Main Component) and in the end it renders the child.
When I stringify the child component props it show only history, location and other props of route, but it's not showing my Users props which is the default state of the app!
And when I use react developer tools it shows there is other router inside my router!
Duplicated Router Screenshot
I found out that when I put the router in something (component, element or whatever like ) it creates another router inside itself and the child router doesn't have the parent props.
I also tried to add
{...this.props}
to routes or
render={(props) => <UserList {props} />}
and also another way that I tried was using nested routes like
const router = (
<Provider store={store}>
<Router history={history}>
<Route path="/" component={App}>
<Route exact component={UsersList}/>
<Route path="/single/:id" component={SingleUser}/>
</Route>
</Router>
</Provider>
);
but the result was this error:
React.cloneElement(...): The argument must be a React element, but you passed undefined.
Thanks.

Since you want to pass the props from App component to UsersList, you need to restructure your Routes differently since with the current way, the props are passed on to the Router, but Router doesn't pass them down to the Route component
index.js
const router = (
<Provider store={store}>
<Router history={history}>
<Route component={App} />
</Router>
</Provider>
);
render(router, document.getElementById('root'));
Main.js
export default class Main extends React.Component {
render() {
return (
<div>
<h1>Hi I'm Header</h1>
<Switch>
<Route exact path="/" render={(routerProps) => <UsersList {...this.props} {...routerProps}/>}/>
</Switch>
</div>
);
}
}

Related

History.push doesn't work in nested child navbar component

I have an app like the following:
<Provider store={store}>
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
</Provider>
Then inside the App component I have the following:
<Layout>
<Route exact path='/' component={Home} />
<Route path='/methodmembers/' component={MethodMembers} />
</Layout>
inside the Layout component I have a child NavMenu component:
return (
<Grid fluid>
<NavMenu/>
</Grid>
)
My problem:
Inside the Layout component, when I do the following with withRouter:
const { history } = this.context.router;
e.preventDefault();
history.push('/methodmembers/');
it works FINE and it redirects me to the desired route.
However, inside the NavMenu component, the same thing does NOT redirect me to another route, it just updates the url.
I am trying withRouter and it still doesn't work.
Does anyone have an idea how to fix this? Thanks
You should pass props to NavMenu like:
return (
<Grid fluid>
<NavMenu {...this.props}/>
</Grid>
)
or you can try to export both component withRouter:
export default withRouter(Layout);
...
export default withRouter(NavMenu);
and pushing route with:
this.props.history.push('/methodmembers/');

React how re-mount component after route change

i'm using react-redux in my project.
I have some component where i'm dispatch some action and get data from reducer into a component on componentWillMount method here is problem when i change to route componentWillMount method not firing my actions or anything else. for that i need to refresh page.
here is my componentWillMount Method:
componentWillMount() {
console.log("d")
this
.props
.getChartData()
data = this.props.chartData
}
and here is my main.js where i import my components and assign routing.
import CompA from 'components/CompA'
import CompB from 'components/CompB'
const App = () => (
<Container fluid>
<div>
<main>
<Switch>
<Route exact path="/page-a" component={ComponentA} />
<Route exact path="/page-b" component={ComponentB} />
</Switch>
</main>
</div>
</Container>
)
export default App
where i mistake or what i need to do with it?
and its index.js:
const target = document.querySelector('#root')
console.log(store.getState())
render(
<Provider store={store}>
<ConnectedRouter history={history}>
<div className="row">
<App />
</div>
</ConnectedRouter>
</Provider>,
target
)
if you use redux you should use mapStateToProps to change the state in your component
I think you are using ConnectedRouter from the package react-router-redux, which is now deprecated.
For react-router 4, You need to use withRouter react-router-dom to wrap the component before connecting it like this:
withRouter(connect(...)(MyComponent))
You can get also get the match, location, history properties via props once the component is wrapped in withRouter.
For further information on withRouter, you can visit the following link: https://reacttraining.com/react-router/web/api/withRouter

when I use history.push url changes but doesn't render the component

I've seen problems like this but neither of them solved my problem.
I have a p tag that onClick is supposed to render a page.
But when I click on it and use this.props.history.push(/posts/${id}) It changes the url but doesn't render the component I want.
I have tried using a
onClick={(e, id) => this.postPage(e, post.id)}
to trigger a function that will trigger the component I want to show up. I also tried using
<Link to-=''>
insted of
<p onClick>
but it doesn't work either.
This is what I have done so far, this is the function that triggers when I click the p tag:
postPage = (e, id) => {
const { history } = this.props;
history.push(`/post/${id.toString()}`);
}
and also, I used withRouter to have access to the history prop.
export default withRouter(connect(null, mapDispatchToProps)(Post));
And these are the routes I mapped:
render() {
return (
<div className="Routes">
<Switch>
<Route exact path='/' component={Home}></Route>
<Route path='/post/:id' render={(history) => (
<PostPage {...history}></PostPage>
)}></Route>
</Switch>
</div>
);
}
}
And of course, when I call this component I also pass using BrowserRouter
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<Routes />
</BrowserRouter>
</Provider>
, document.getElementById('root'));
I just wanted to render the component but only the URL changes and nothing happens.
A good approach would be to implement react-redux and react-router-dom one at a time, to ensure that there are no clashes. The double HOC here:
export default withRouter(connect(null, mapDispatchToProps)(Post));
Is worth breaking down to:
export default withRouter(Post);
To ensure that react-router-dom works as expected, then implementing react-redux once routing is in place.
For those who have had the same problem the solution was to change the BrowserRouter tag location from the index.js to inside of the component that uses the Route. I was doing something like:
ReactDOM.render(<Provider>
<BrowserRouter>
<App>
</BrowserRouter>
</Provider>, document.getElementById('root'));
and now inside the Routes.js component
render() {
<BrowserRouter>
<Route ...>
<Route ...>
</BrowserRouter>
}

Redirecting with react-router in a react redux app

I am trying to implement routing for my app which is built with react and redux. I have wrapped in so that route handlers can get access to the store.But somehow my routing logic is not working.
This piece of code was working fine
export default class Root extends Component {
render() {
return (
<Provider store={this.props.store}>
<div>
<App />
</div>
</Provider>
);
}
}
But when I replace with the below code it is not showhing anything on my localhost.
export default class Root extends Component {
render() {
return (
<Provider store={this.props.store}>
<div>
<Router>
<Route path="/" component={App} />
</Router>
</div>
</Provider>
);
}
}
I am trying to figure out what I am doing wrong. Any help will be appreciated.
I am assuming your project is browser based project. So , you can make use of <BrowserRouter> if your website/app is hosted on a dynamic server.
You can wrap it like :
import {BrowserRouter, Route} from 'react-router-dom';
export default class Root extends Component {
render() {
return (
<Provider store={this.props.store}>
<div>
<BrowserRouter>
<Route path="/" component={App} />
<BrowserRouter>
</div>
</Provider>
);
}
}
if your web is backed by static server make use of <HashRouter>
You can read more Here
I think you're supposed to use one of the higher level router components like BrowserRouter. See if this works:
return (
<Provider store={this.props.store}>
<div>
<BrowserRouter>
<Route path="/" component={App} />
</BrowserRouter>
</div>
</Provider>
);

React router not rendering inactive route components

I started with create-react-app and am attempting to set up auth-based routing via a Gatekeeper component. Right now the only thing the Gatekeeper component does is render its children. I use redux to get the current user from the state tree and save it as currentUser. I'll use that to validate access to the child routes later.
import React from 'react';
import { connect } from 'react-redux';
import { subscribeToCurrentUser } from '../../reducers/authentication';
class Gatekeeper extends React.Component {
componentDidMount() {
this.props.subscribeToCurrentUser();
}
render() {
return this.props.children
}
}
function mapStateToProps(state) {
return {
currentUser: state.currentUser
}
}
const GatekeeperContainer = connect(mapStateToProps, {subscribeToCurrentUser})(Gatekeeper);
export default GatekeeperContainer;
If I initially load the app on, say /account everything loads as expected. But if I navigate to /templates/123 via a <NavLink> the URL changes but the <Template> component doesn't render. Inspecting with React Dev Tools shows me the children of every route underneath the Gatekeeper component is null. If I refresh the page then the <Template> component renders as expected but navigating back to /account doesn't render the <AccountPage> component.
<Provider store={store}>
<Router history={history}>
<div>
<Route exact path="/" component={LandingPage} />
<Layout>
<Route path="/login" component={Login} />
<Gatekeeper>
<Switch>
<Route path="/home" component={HomePage} />
<Route path="/templates/:templateID" component={Template} />
<Route path="/account" component={AccountPage} />
</Switch>
</Gatekeeper>
</Layout>
</div>
</Router>
</Provider>
What am I doing wrong here?

Resources