Can't render children (let alone routed children) inside routed react component - reactjs

Building my first React app and I am trying to create a nested router within the authenticated 'internal' page but it's proving quite difficult. I've tried a number of things, but this is the latest incarnation--and I am getting a cannot read 'children' property of undefined error in the AuthenticatedFrame component.
export class NavigationFrame extends React.Component<INavigationFrameProps, {}> {
render() {
console.log(this.props)
console.log(this.state)
console.log(this.props.store.store.getState())
return <Router>
<div className="navigation-frame">
<Route exact path="/" component={Splash}/>
<Route exact path="/register" component={RegistrationForm}/>
<Route path="/signin" component={SignInContainer}/>
<Route path="/i" render={() => (
this.props.store.store.getState().authenticationState.authenticated ? (
<AuthenticatedFrame>
<Route exact path="/i/" component={WelcomePage}/>
<Route path="/i/add" component={AddPage}/>
</AuthenticatedFrame>
) : (
<Redirect to="/signin"/>
)
)}/>
</div>
</Router>;
}
}
And my AuthenticatedFrame (doesn't work)
export const AuthenticatedFrame = () => (
<div className="internal-view">
<SidebarDrawer />
<div className="content-area">
{this.props.children}
</div>
</div>)

AuthenticatedFrame is a functional component and hence doesn't have access to this keyword, you need to access props as function arguments like
export const AuthenticatedFrame = (props) => (
<div className="internal-view">
<SidebarDrawer />
<div className="content-area">
{props.children}
</div>
</div>
)

Urf. I just had to change out Authenticated Frame with this:
export class AuthenticatedFrame extends React.Component<{children: any}, {}> {
render() { return <div className="internal-view">
<SidebarDrawer />
<div className="content-area">
{this.props.children}
</div>
</div>}

Related

route is not loading component inside nested route component

I'm loading my adminDashboard component in app.js with Route. now in adminDashboard based on URL, I want to render some component. but, it's not loading any component. also, there is no activity on the network tab in chrome console.
if I render them without Route, they are rendering properly.
app.js
class App extends Component {
render() {
let { error, success } = this.props;
const Admin = Authorization(['admin'])
return (
<div className='app'>
<AdminNavbar logout={this.props.logout}/>
<Switch>
<Route exact path='/admin/signin' render={(props) => {
return <AuthForm />
}}
/>
<Route exact path='/admin' component={Admin(AdminDashboard)} />
</Switch>
<Footer />
</div>
);
}
}
MyComponent component
const MyDashboard = (props)=> ` this is dashboard`
Admindashboard
class AdminDashboard extends Component{
render() {
return (
<div>
<div className='row'>
<div className='col-md-2'>
<NavBar />
</div>
<div className='col-md-10'>
< Commisions /> //working properly if i load it without route
<Switch>
<Route exact path='/admin/dashboard' component={MyDashboard} /> // not work
//some other route
</Switch>
</div>
</div>
</div>
)
}
}

Carry ownProps deep react router

I am trying to gain access to params in ownProps. Is there a way to solve this?
Current structure is
const Router = () => (
<router>
<Switch>
<Route path='/signup' component={Signup} />
<Route path='/browse' component={Browse}/>
<Route path='/detail/:id' component={Detail} />
</Switch>
</router>
)
i want ownProps to pass on to these pages in Detail
export default class App extends Component {
render() {
return (
<div>
<Info />
<Message/>
</div>
);
}
}
After messing around I found a way which is that I passed the required information as props to nested components.
export default class App extends Component {
render() {
return (
<div>
<Info idInfo={this.props}/>
<Message idInfo={this.props}/>
</div>
);
}
}
after this I got information in ownProps.

React Router: Get location in container component

I need to access the active path in the parent component, so that I can vary some CSS depending on the location. Here is App - the parent:
class App extends React.Component {
render(){
return (
<div className="wrapper" >
<div className="content">
<Router>
<div className="container_b">
<Menu />
<div>
<Route exact path="/" component={Home}/>
<Route path="/confidence" component={ConfidenceInterval}/>
<Route path="/proind" component={ProportionTestInd}/>
<Route path="/prodep" component={ProportionTestDep}/>
</div>
</div>
</Router>
<div className="push"></div>
</div>
<footer className="footer"><Footer /></footer>
</div>
)
}
}
I think for the App component, you have two options. First one is wrapping App with withRouter higher order component.
React-router provides a higher order component called withRouter, which passes match, history and location props to the component wrapped by it.
(for details please check withRouter)
In that case you can to the following
class App extends React.Component {
render(){
const {location: {pathname}} = this.props // pathname gives you the current path
return (
<div className="wrapper" >
<div className="content">
<Router>
<div className="container_b">
<Menu />
<div>
<Route exact path="/" component={Home}/>
<Route path="/confidence" component={ConfidenceInterval}/>
<Route path="/proind" component={ProportionTestInd}/>
<Route path="/prodep" component={ProportionTestDep}/>
</div>
</div>
</Router>
<div className="push"></div>
</div>
<footer className="footer"><Footer /></footer>
</div>
)
}
}
export const WrappedApp = withRouter(App)
Second option is, (again for App component) you can use window.location (please check window.location). location.pathname should also give you the current path in that case.
For other components, like Home,ConfidenceInterval etc, Route passes match, history and location props by default so you can make use of them.
import {useLocation} from 'react-router-dom'
const App = () => {
const location = useLocation();
console.log(location.pathname);
enter code herereturn <span>Path : {location.pathname}</span>
}

Multiple Layouts with React Router v4

I'm pulling my hair out trying to render multiple layouts with React Router v4.
For instance, I'd like pages with the following paths to have layout 1:
exact path="/"
path="/blog"
path="/about"
path="/projects"
and the following paths to have layout 2:
path="/blog/:id
path="/project/:id
Effectively what's being answered here but for v4: Using multiple layouts for react-router components
None of the other answers worked so I came up with the following solution. I used the render prop instead of the traditional component prop at the highest level.
It uses the layoutPicker function to determine the layout based on the path. If that path isn't assigned to a layout then it returns a "bad route" message.
import SimpleLayout from './layouts/simple-layout';
import FullLayout from './layouts/full-layout';
var layoutAssignments = {
'/': FullLayout,
'/pricing': FullLayout,
'/signup': SimpleLayout,
'/login': SimpleLayout
}
var layoutPicker = function(props){
var Layout = layoutAssignments[props.location.pathname];
return Layout ? <Layout/> : <pre>bad route</pre>;
};
class Main extends React.Component {
render(){
return (
<Router>
<Route path="*" render={layoutPicker}/>
</Router>
);
}
}
simple-layout.js and full-layout.js follow this format:
class SimpleLayout extends React.Component {
render(){
return (
<div>
<Route path="/signup" component={SignupPage}/>
<Route path="/login" component={LoginPage}/>
</div>
);
}
}
So, for this you should use render function (https://reacttraining.com/react-router/core/api/Route/render-func)
A really good article that helped me: https://simonsmith.io/reusing-layouts-in-react-router-4/
In the end you will be use something like this:
<Router>
<div>
<DefaultLayout path="/" component={SomeComponent} />
<PostLayout path="/posts/:post" component={PostComponent} />
</div>
</Router>
I solved this problem utilizing a bit of both of your solutions:
My Routes.js file
import BaseWithNav from './layouts/base_with_nav';
import BaseNoNav from './layouts/base_no_nav';
function renderWithLayout(Component, Layout) {
return <Layout><Component /></Layout>
}
export default () => (
<Switch>
{/* Routes with Sidebar Navigation */}
<Route exact path="/" render={() => renderWithLayout(Home, BaseWithNav)} />
{/* Routes without Sidebar Navigation */}
<Route path="/error" render={() => renderWithLayout(AppErrorMsg, BaseNoNav)} />
<Route path="/*" render={() => renderWithLayout(PageNotFound, BaseNoNav)} />
</Switch>
)
Base.js (where routes get imported)
export default class Base extends React.Component {
render() {
return (
<Provider store={store}>
<Router>
<Routes />
</Router>
</Provider>
)
}
}
Layouts
BaseWithNav.js
class BaseWithNav extends Component {
constructor(props) {
super(props);
}
render() {
return <div id="base-no-nav">
<MainNavigation />
<main>
{this.props.children}
</main>
</div>
}
}
export default BaseWithNav;
BaseNoNav.js
class BaseNoNav extends Component {
constructor(props) {
super(props);
}
render() {
let {classes} = this.props;
return <div id="base-no-nav">
<main>
{this.props.children}
</main>
</div>
}
}
export default BaseNoNav;
I hope this helps!
I know i am replying late but it's easy to do that, i hope it will helps to newbie.
i am using React 4
Layout.js
export default props => (
<div>
<NavMenu />
<Container>
{props.children}
</Container>
</div>
);
LoginLayout.js
export default props => (
<div>
<Container>
{props.children}
</Container>
</div>
);
Now finally we have our App
App.js
function renderWithLoginLayout(Component, Layout) {
return <LoginLayout><Component /></LoginLayout>
}
function renderWithLayout(Path, Component, Layout) {
return <Layout><Route path={Path} component={Component} /></Layout>
}
export default () => (
<Switch>
<Route exact path='/' render={() => renderWithLayout(this.path, Home, Layout)} />
<Route path='/counter' render={() => renderWithLayout(this.path, Counter, Layout)} />
<Route path='/fetch-data/:startDateIndex?' render={() => renderWithLayout(this.path, FetchData, Layout)} />
<Route path='/login' render={() => renderWithLoginLayout(Login, LoginLayout)} />
</Switch>
);

ReactJS - Change Component in parent depending on nested route

I have my App wrapped in a component which renders a Header, Footer and any routed child components.
I am trying to replace the <Header /> component with </HeaderAdmin/> when at /admin.
Routes
<Route path='/' component={SiteWrapper} >
<IndexRoute component={Home} />
<Route path="admin" component={Admin}>
<Route path="dashboard" component={Dashboard}/>
</Route>
</Route>
SiteWrapper Comp
export default class SiteWrapper extends React.Component {
render() {
return (
<div>
<Header/> // Want to replace with <AdminHeader /> if on /admin
<div className="container">
{this.props.children.props.route.header ? <PageHeader header={this.props.children.props.route.header} /> : null}
{this.props.children}
</div>
<Footer/>
</div>
)
}
}
You can use this.props.location.pathname to find the route name
export default class SiteWrapper extends React.Component {
render() {
return (
<div>
{(this.prop.location.pathname === 'admin')? <AdminHeader/>: <Header/>}
<div className="container">
{this.props.children.props.route.header ? <PageHeader header={this.props.children.props.route.header} /> : null}
{this.props.children}
</div>
<Footer/>
</div>
)
}
}
For that, I think you can check the route by window.location or this.props.location.pathname, it will contain the route names, if the route name is /admin then render the Header component otherwise render the AdminHeader component.
Write it like this:
{ this.prop.location.pathname === '/admin'? <AdminHeader/>: <Header/>}

Resources