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.
Related
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?
Ok so first of all let me give routes i am using
<Header />
<Routes>
<Route path="/" element={<Navigate replace to="/all" />} />
<Route path="/product" element={<ProductDetail />} />
<Route path="/cart" element={<Cart />} />
<Route path="/:category" element={<ProductListing products={this.state.products} />} />
</Routes>
So i have the path category
<div className="right__bar">
<div className='nav_link'><Link to={"/all"}>ALL</Link></div>
<div className='nav_link'><Link to={"/clothes"}>CLOTHES</Link></div>
<div className='nav_link'><Link to={"/tech"}>TECH</Link></div>
<div className='nav_link'><Link to={"/cart"}>CART</Link></div>
</div>
When I am clicking the link All and then click clothes the ProductListing component does not re-render maybe because they are using the same props and the same component they have an implementation difference when I click on Clothes from the list of products it just shows the clothes category product
Below there I am pasting my ProductListing component
import React, { Component } from 'react';
// import { useParams } from 'react-router-dom';
import { Card } from '../../components'
import "./ProductListing.scss"
export class ProductListing extends Component {
constructor(props){
super(props);
this.state ={
productsToRender:{},
loading:true,
}
}
componentDidMount(){
let {products} = this.props;
const currentUrl = window.location.href;
// I am checking if the all is present in the url i will set productsToRender
// I am facing a weired issue that is the props are not accessible to the inside if blocks
if(currentUrl.search("all")!==-1){
this.setState({
productsToRender:products[0],
loading:false,
})
}else if(currentUrl.search("clothes")!==-1){
this.setState({
productsToRender:products[1],
loading:false,
})
}else if(currentUrl.search("tech")!==-1){
this.setState({
productsToRender:products[2],
loading:false,
})
}
}
render() {
console.log("I am executed")
if(this.state.loading === true){
return <h1>LOADING....</h1>
}else{
return (
<div>
<h2>{this.state.productsToRender.name}</h2>
<div className="product__listing">
{this.state.productsToRender.products.map((item,index)=>(
<Card product={item}/>
))}
</div>
</div>
)
}
}
}
export default ProductListing
Instead of taking window.location.href you could use useParams hook, which would return your current :category
I am putting together a small application to get used to React, now I have installed React-Router-Dom and when I click a link the URL correctly changes. The issue is that the correct Component does not display.
index.js
ReactDOM.render(
<Router>
<App />
</Router>,
document.getElementById('root')
);
registerServiceWorker();
App.js
import React, { Component } from 'react';
import Sidebar from './Components/Sidebar';
import SidebarItem from './Components/SidebarItem';
import Home from './Components/Home';
import './App.scss';
import { Link, Route, Switch } from 'react-router-dom';
class App extends Component {
constructor() {
super();
this.state = {};
}
render() {
return (
<div className="App">
<Link to='/home'>Home</Link>
<Switch>
<Route path='/home' Component={Home} />
</Switch>
</div>
);
}
}
export default App;
Can anyone tell me the reason why HomeComponent does not appear?
The prop of the Route that takes a component is spelled component with a small c, not Component.
Example
function Home() {
return <div> Home </div>;
}
class App extends Component {
render() {
return (
<Router>
<div>
<Link to="/home">Home</Link>
<Switch>
<Route path="/home" component={Home} />
</Switch>
</div>
</Router>
);
}
}
I want to be able to have a Portfolio page (example.com/portfolio), and a dynamic route for individual case studies (example.com/portfolio/case-study/dynamic-url-slug). Currently, the new component that should render in its own page is still rendering within the page (understandable, as the markup declares the route within the containing div). But how do I get it to render on its own page?
App.js (where all routes are declared)
import React, { Component } from 'react';
import { Switch, Route } from 'react-router-dom';
import Home from './components/Pages/Home/Home';
import About from './components/Pages/About/About';
import Portfolio from './components/Pages/Portfolio/Potfolio';
import CaseStudy from './components/Pages/Portfolio/CaseStudyPage';
export default class App extends Component {
render() {
return (
<div className="icon-container" id="outer-container">
<div className="pages">
<Switch>
<Route exact path='/' component={ Home } />
<Route path='/about' component={ About } />
<Route path='/portfolio' component={ Portfolio } />
<Route exact path={`/portfolio/case-study/:caseSlug`}
render={(props) => <CaseStudy />} />
</Switch>
</div>
</div>
)
}
}
Portfolio.js
import React, { Component } from 'react';
import '../styles/vendor/swiper/swiper.min.css';
import Swiper from 'react-id-swiper';
import { Link, Route } from 'react-router-dom';
import CaseStudyPage from './Pages/Work/CaseStudyPage';
const case_studiesURL = "http://myprivateblogapi.com/wp-json/wp/v2/case_studies?_embed";
const case_URL = '/portfolio/case-study/';
export default class Portfolio extends Component {
constructor(props) {
super(props);
this.state = {
case_studies: [],
isLoading: true,
requestFailed: false
}
}
componentDidMount() {
fetch(case_studiesURL)
{/* fetching all the appropriate data */}
}
renderPortfolioItem(data) {
return props => <CaseStudyPage data={data} {...props} />
}
render() {
if(this.state.isLoading) return <span>Loading...</span>
const params = {
{/* swiper parameters */}
}
let case_studies_items = this.state.case_studies.map((case_studies_item, index) => {
return (
<div className="portfolio-slide" id={`swiper-slide-${index}`}
key={index}
>
<Link className="portfolio-link"
to={`${case_URL}${case_studies_item.slug}`}>
<h3 className="portfolio-swiper--slide-title"> {case_studies_item.title.rendered}</h3>
</Link>
<Route exact path={`${case_URL}:caseSlug`}
render={this.renderPortfolioItem(case_studies_item)} />
</div>
)
});
return(
<div className="portfolio-swiper--container">
<Swiper {...params}>
{case_studies_items}
</Swiper>
</div>
)
}
}
You should define a route for each different views in react router,
<Switch>
<Route exact path='/' component={ Home } />
<Route exact path='/about' component={ About } />
<Route exact path='/portfolio' component={ Portfolio } />
<Route exact path='/portfolio/case-study' component={ CaseStudy } />
<Route exact path='/portfolio/case-study/:caseSlug' component {CaseStudyDetails} />
</Switch>
and you don't need to create a render method to pass props to your view components. You can easily reach router props inside of a react component if it is already rendered into Router,
this.props.match
this.props.location
this.props.history
as an example you can get your dynamic parameter inside of CaseStudy component like,
this.props.match.caseSlug
I am trying to pass a value from the render function to the component:
= react_component('App', props: {test: 'abc'}, prerender: false)
Routes.jsx
<Route path="/" component={App} >
App.jsx (component)
class App extends React.Component {
render() {
return (
<Header test={this.props.test}>
</Header>
{this.props.children}
<Footer />
);
}
}
App.propTypes = { test: PropTypes.string };
There does not seem to be a coherent answer to this complete flow.
I have tried the following:
<Route path="/" component={() => (<App myProp="value" />)}/>
But this still does not answer the question of picking up the value provided by the initial render call(react_component)
Looking for an end to end answer on how to pass a parameter from the
"view" to the "react router" to the "component"
We will start from the view:
<%= react_component('MyRoute', {test: 123}, prerender: false) %>
Now we will create a component that holds our route:
class MyRoute extends Component{
constructor(props){
super(props)
}
render(){
return(
<Switch>
<Route path="/" render={() => <App test={this.props.test} />} />
<Route path="/login" component={Login} />
</Switch>
)
}
}
As you can see, we passed the test prop from the Route component to the App component. Now we can use the test prop in the App component:
class App extends Component{
constructor(props){
super(props)
}
render(){
return(
<h1>{this.props.test}</h1>
)
}
}
<Route path="/" render={attr => <App {...attr} test="abc" />} />
In Router v3 you would do something like this
Wrap your App component under withRouter like this
import { withRouter } from 'react-router';
class App extends React.Component {
render() {
return (
<Header test={this.props.test}>
</Header>
{
this.props.children &&
React.clone(this.props.children, {...this.props} )}
<Footer />
);
}
}
App.propTypes = { test: PropTypes.string };
export const APP = withRouter(App);
And construct your routes like this...
<Route path="/" component={APP}>
<Route path="/lobby" component={Lobby} />
<Route path="/map" component={GameMap} />
...
</Route>
So your child routes will be rendered inside the APP children property an the props will be passed down to them.
Hope this helps!