Unable to integrate a React ErrorBoundary - javascript

I have an ErrorBoundary class (ErrorBoundry.jsx) that looks like this:-
import React, { Component } from 'react'
import ErrorPage from '../../ErrorPage'
const WithErrorBoundary = ({ renderError } = {}) => {
return WrappedComponent => {
return class ErrorBoundary extends Component {
state = { error: null }
componentDidCatch(error, errorInfo) {
this.setState({ error })
}
render() {
if (this.state.error) {
return <ErrorPage />
}
return <WrappedComponent {...this.props} />
}
}
}
}
export default WithErrorBoundary;
The fallback UI (ErrorPage) looks like this:-
import React from 'react';
import { useTranslation } from 'react-i18next';
import classNames from 'classnames';
import Logo from '../../../../../images/logo.svg';
import styles from './styles.module.css';
export default function ErrorPage(props) {
const { t } = useTranslation('common');
return (
<>
<div className={classNames('navbar', 'navbar-fixed-top', styles.headerSection)}>
<div className={classNames('col-md-12', 'col-xs-12' , styles.logoSection)}>
<span className={styles.logo}>
<img className='img-fluid' src={Logo} alt='Logo' />
</span>
</div>
</div>
<div className={styles.content}>
<div className={styles.unavailableDiv}>
<h1>{t('unavailable_page_title')}</h1>
<p>{t('unavailable_page_message_1')}</p>
<p>{t('unavailable_page_message_2')}</p>
</div>
</div>
</>
);
};
I am wrapping my routes in app.jsx with the ErrorBoundary like this:-
const ErrorBoundary = lazy(() => import('./components/core/ErrorBoundary/ErrorBoundry'));
<ErrorBoundary>
<Switch>
<Redirect from='/' to='/notfound' exact />
<Redirect from='/:country/ord' to='/notfound' exact />
<Route path='/notfound' component={NotFound} />
<PrivateRoute path='/:country/' exact component={Payment} />
<PrivateRoute path='/:country/:encryptedParams' exact component={DetailPage} />
<Route component={NotFound} />
</Switch>
</ErrorBoundary>
When I run my app, I get a blank page with a console error:-
Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it.
I went through the answers in Functions are not valid as a React child. This may happen if you return a Component instead of from render, but they didn't quite help me. Where exactly am I going wrong?

Related

Component is not Getting Rendered - Dynamic Routing React

I can get the data of the players when i Route to the Players Component,
but when i click on the Link Tags, the PLayersContainer Component is not opening.
This is my App.js File.
import React, { Component } from 'react'
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'
import Players from './Components/Players'
import PlayersContainer from './Components/Container/playersContainer'
import Navigation from './Components/Navigation';
export default class App extends Component {
state = {
players:[
{
id:1,
name:'Ronaldo'
},
{
id:2,
name:'Messi'
}
]
}
render() {
return (
<Router>
<Navigation />
<Switch>
<Route path="/players" render={(props) => <Players {...props} players={this.state.players} />} />
<Route exact path="/players/:id" render={PlayersContainer} />
</Switch>
</Router>
)
}
}
This is my Players Component.
import React from 'react'
import { Link } from 'react-router-dom'
export default function Players(props) {
const renderPlayers = () => {
let players = props.players.map(playerObj => <li> <Link to={`/players/${playerObj.id}`}> Player {playerObj.name} </Link></li>)
return players
}
return (
<div>
<ul>
{renderPlayers()}
</ul>
</div>
)
}
This is my PlayersContainer Component, where i want to render the individual data of the Player.
import React from 'react'
import { Link } from 'react-router-dom'
export default function PlayersContainer(props) {
const renderPlayers = () => {
console.log(props);
}
return (
<div>
<ul>
{renderPlayers()}
</ul>
</div>
)
}
You have the wrong Route marked as exact. The way its written currently, anything beginning with /players will match the first route. Since its in a switch, only the first match will be rendered.
Change it from:
<Route path="/players" render={(props) => <Players {...props} players={this.state.players} />} />
<Route exact path="/players/:id" render={PlayersContainer} />
to this:
<Route exact path="/players" render={(props) => <Players {...props} players={this.state.players} />} />
<Route path="/players/:id" render={PlayersContainer} />
Now only exactly /players will match the first route, and /players/id can continue past it to match the second.

Getting the value of Props parameter as undefined (ReactJS)

I'm having an attribute in one of the components and when I'm trying to access that attribute via props, I'm getting its value as undefined.
Below is the piece of code where I'm making use of the component and passing the required attribute.
import React, { Component } from "react";
import PageNotFound from "./pages/page-not-found";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import BookSectionPage from "./pages/books-section";
import BookDetails from "./pages/book-details";
class App extends Component {
render() {
return (
<div>
<BrowserRouter>
<Switch>
<Route path="/" exact component={BookSectionPage}/>
<Route path="/book/category/:categoryName" exact render = { (props) => {
return <BookSectionPage title = "JavaScript" /> // This is the component
}} />
<Route path="/book/:bookID" exact component={BookDetails} />
<Route component={PageNotFound} />
</Switch>
</BrowserRouter>
</div>
);
}
}
export default App;
Below is the code for the component where I'm trying to access the above-mentioned attribute via Props but getting its value as undefined.
import React from "react";
import Header from "../components/header/header";
import Footer from "../components/Footer/footer";
import BookSectionComponent from "../components/books-section/books-section";
const BookSectionPage = (Props) => {
let books=[1,2,3,4,5,6];
console.log(Props.title); // Here instead of printing the value of attribute, it's showing undefined.
return (
<div className="has-fixed-footer">
<Header />
<BookSectionComponent title = {Props.title} books = {books} />
<Footer />
</div>
);
};
export default BookSectionPage;
Any help would be highly appreciated. Thanks!
From Parent to Child Using Props
App
└── Parent
├── Child1
Most easiest direction of data flow in React and basic example.
Parent Component
class Parent extends React.Component {
state = { title : "JavaScript" }
render() {
return (
<div>
<Child1 dataFromParent = {this.state.title} />
</div>
);
}
}
Child Component
class Child1 extends React.Component {
render() {
return (
<div>
The data from parent is:{this.props.dataFromParent}
</div>
);
}
}

History not accessible from react-router-modal

Hello I'm having a problem with setting 'react-router-modal' parentPath for the last used component
ModalRoute and ModalContainer are a part of
react-router-modal
App.js
class App extends Component {
render() {
return (
<main>
<Navbar />
<BrowserRouter>
<div>
<Switch>
<Route path="/main" component={ContentDefault} />
<Route path="/search" component={SearchScreen} />
<ModalRoute
path="/register"
parentPath="/"
component={RegisterScreen}
/>
<Route path="/contact" component={ContentDefault} />
<Route component={ContentDefault} />
</Switch>
<ModalContainer />
</div>
</BrowserRouter>
<Footer />
</main>
);
}
}
export default App;
SearchScreen.jsx
import React, { Component } from "react";
import { withRouter } from "react-router-dom";
class SearchScreen extends Component {
render() {
return (
<main>
<h1>SearchScreen</h1>
</main>
);
}
}
export default withRouter(SearchScreen);
For Example i'm on mainScreen then i move to the SearchScreen then i open modal from navbar. I need my modal to go back to the SearchScreen
I found couple of solutions which may help you.
You can try with this:
Create state prevPath
Add componentWillReceiveProps
Provide prevPath state to the parentPath with condition if prevPath is empty redirect me on route '/'
class App extends Component {
state = {
prevPath: ''
}
componentWillReceiveProps(nextProps) {
if (nextProps.location !== this.props.location) {
this.setState({ prevPath: this.props.location })
}
}
<ModalRoute
path="/register"
parentPath={this.state.prevPath || '/'}
component={RegisterScreen}
/>
This is one of the solutions we can try later another one if this doesn't help.

How to handle Authentication with react-router?

Trying to make certain routes require Authentication.
I have this:
class App extends Component {
render() {
const menuClass = `${this.props.contentMenuClass} col-xs-12 col-md-9`;
return (
<BrowserRouter history={browserHistory}>
<div className="App">
<Header properties={this.props} />
<div className="container-fluid">
<div className="row">
<SideNav />
<div className={menuClass} id="mainContent">
<Switch>
{routes.map(prop =>
(
<Route
path={prop.path}
component={prop.component}
key={prop.id}
render={() => (
!AuthenticationService.IsAutheenticated() ?
<Redirect to="/Login"/>
:
<Route path={prop.path}
component={prop.component}
key={prop.id}/>
)}
/>
))}
</Switch>
</div>
</div>
</div>
{/* <Footer /> */}
</div>
</BrowserRouter>
);
}
}
const mapStateToProps = state => ({
contentMenuClass: state.menu,
});
export default connect(mapStateToProps)(App);
Note: Yes the auth service works as it should.
For every route I am checking if the user is authenticated, if not then I want to redirect them to the login page, if they are then it will land on the first page with the route of "/".
All I am getting is:
react-dom.development.js:14227 The above error occurred in the <Route> component:
in Route (created by App)
in Switch (created by App)
in div (created by App)
in div (created by App)
in div (created by App)
in div (created by App)
in Router (created by BrowserRouter)
in BrowserRouter (created by App)
in App (created by Connect(App))
in Connect(App)
in Provider
Where am I doing this wrong?
A simple solution would be to make a HOC (High Order Component) that wraps all protected routes.
Depending upon how nested your app is, you may want to utilize local state or redux state.
Working example: https://codesandbox.io/s/5m2690nn6n (this uses local state)
routes/index.js
import React from "react";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import Home from "../components/Home";
import Players from "../components/Players";
import Schedule from "../components/Schedule";
import RequireAuth from "../components/RequireAuth";
export default () => (
<BrowserRouter>
<RequireAuth>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/players" component={Players} />
<Route path="/schedule" component={Schedule} />
</Switch>
</RequireAuth>
</BrowserRouter>
);
components/RequireAuth.js
import React, { Component, Fragment } from "react";
import { withRouter } from "react-router-dom";
import Login from "./Login";
import Header from "./Header";
class RequireAuth extends Component {
state = { isAuthenticated: false };
componentDidMount = () => {
if (!this.state.isAuthenticated) {
this.props.history.push("/");
}
};
componentDidUpdate = (prevProps, prevState) => {
if (
this.props.location.pathname !== prevProps.location.pathname &&
!this.state.isAuthenticated
) {
this.props.history.push("/");
}
};
isAuthed = () => this.setState({ isAuthenticated: true });
unAuth = () => this.setState({ isAuthenticated: false });
render = () =>
!this.state.isAuthenticated ? (
<Login isAuthed={this.isAuthed} />
) : (
<Fragment>
<Header unAuth={this.unAuth} />
{this.props.children}
</Fragment>
);
}
export default withRouter(RequireAuth);
Or, instead of wrapping routes, you can create a protected component that houses protected routes.
Working example: https://codesandbox.io/s/yqo75n896x (uses redux instead of local state).
routes/index.js
import React from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import { createStore } from "redux";
import { Provider } from "react-redux";
import Home from "../components/Home";
import Header from "../containers/Header";
import Info from "../components/Info";
import Sponsors from "../components/Sponsors";
import Signin from "../containers/Signin";
import RequireAuth from "../containers/RequireAuth";
import rootReducer from "../reducers";
const store = createStore(rootReducer);
export default () => (
<Provider store={store}>
<BrowserRouter>
<div>
<Header />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/info" component={Info} />
<Route path="/sponsors" component={Sponsors} />
<Route path="/protected" component={RequireAuth} />
<Route path="/signin" component={Signin} />
</Switch>
</div>
</BrowserRouter>
</Provider>
);
containers/RequireAuth.js
import React from "react";
import { Route, Redirect } from "react-router-dom";
import { connect } from "react-redux";
import ShowPlayerRoster from "../components/ShowPlayerRoster";
import ShowPlayerStats from "../components/ShowPlayerStats";
import Schedule from "../components/Schedule";
const RequireAuth = ({ match: { path }, isAuthenticated }) =>
!isAuthenticated ? (
<Redirect to="/signin" />
) : (
<div>
<Route exact path={`${path}/roster`} component={ShowPlayerRoster} />
<Route path={`${path}/roster/:id`} component={ShowPlayerStats} />
<Route path={`${path}/schedule`} component={Schedule} />
</div>
);
export default connect(state => ({
isAuthenticated: state.auth.isAuthenticated
}))(RequireAuth);
You can even get more modular by creating a wrapper function. You would be able to pick and choose any route by simply wrapping over the component. I don't have a codebox example, but it would be similar to this setup.
For example: <Route path="/blog" component={RequireAuth(Blog)} />
You spelled Autheenticated wrong.
Also, this is an assumption because you only provided the stack trace and not the above error, which probably says AuthenticationService.IsAutheenticated is not a function.

React-router-dom v.4 BrowseRouter pass function to child

I have just upgraded to React-Router v.4 (and redux-saga). But I am having problems with passing functions from parent container to child inside a route...
Parent:
import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { BrowserRouter as Router, Route, NavLink } from 'react-router-dom';
import { fetchGalleryImages } from './business_logic/modules/gallery'
import logo from './assets/images/saga-logo.png';
import Gallery from './components/Gallery';
function mapStateToProps(state) {
return { galleryImages: state.galleryImages };
}
function mapDispatchToProps(dispatch) {
return { actions: bindActionCreators({ fetchGalleryImages }, dispatch) };
}
class App extends Component {
constructor(props) {
super(props);
this.loadGallery = props.actions.fetchGalleryImages.bind(this);
}
loadGalleryHandler() {
this.loadGallery();
}
render() {
return (
<div className="App">
<img src={logo} className="logo" alt="logo" />
<h1>Welcome to Redux-Saga</h1>
<section className="content">
<p>This is an exersize in using react together with Redux-saga.</p>
<Router>
<div>
<nav className="main">
<NavLink activeClassName="selected" exact to="/" >Home</NavLink>
<NavLink activeClassName="selected" to="/gallery">Gallery</NavLink>
</nav>
<Route path="/gallery" onLoadEvent={this.loadGalleryHandler} component={Gallery} />
</div>
</Router>
</section>
</div>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
My child component looks like this:
import React, { Component } from 'react';
class Gallery extends Component {
componentDidMount() {
this.props.onLoadEvent();
}
render() {
return (
<div className="Gallery">
<h2>Gallery</h2>
</div>
);
}
}
export default Gallery;
As you can see I am trying to pass the function loadGallery to the Gallery component, however, in the dom the Gallery component gets wrapped in a Route component which does not send the loadGallery function on to its child.
This is what it looks like in React's dom:
<Route path="/gallery" onLoadEvent=loadGalleryHandler() component=Gallery()>
<Gallery match={...somestuff...} location={...somestuff...} history={...somestuff...}>...</Gallery>
</Route>
Clearly the onLoadEvent=loadGalleryHandler() is not passed to Gallery.
How do I make it work?
As you noticed, that props you pass to <Route> won't be passed down to your component. This is the exact use case for a Route's render prop.
Instead of this,
<Route path="/gallery" onLoadEvent={this.loadGalleryHandler} component={Gallery} />
You can do this and then pass any props to your component that you'd like,
<Route path="/gallery" render={() => (
<Gallery {...props} onLoadEvent={this.loadGalleryHandler} />
)} />

Categories

Resources