react-router v4: How to create a contentFor like feature? - javascript

I have this:
import { Route } from 'react-router-dom'
const App = () => (
<div>
{header} // or the header block
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
</div>
)
Then my About component looks like this:
const About = () => {
// contentFor header
const myCustomHeader = <div>About header</div>
return (
<div>
About page
</div>
)
}
Is there a way to replace the header in the App component with the myCustomHeader component from the About component ?

You can pass a function prop to update the parents state. You'll have to use render instead of component on your Route to pass props.
import { Route } from 'react-router-dom'
import React from 'react'
class App extends React.Component{
state = {
header:"One Header"
}
render(){
return (
<div>
{this.state.header} // or the header block
<Route exact path="/" component={Home} />
<Route path="/about" render={()=><About updateHeader={(newHeader)=>this.setState({header:newHeader})} />}/>
</div>
)
}
}
And your About :
import React from 'react'
class About extends React.Component{
render(){
this.props.updateHeader(<div>About header</div>);
return (
<div>
About page
</div>
)
}
}

Related

react router path parameter not working in class component

Well, I defined the react router as follows:
<BrowserRouter>
<Routes>
<Route path="/" exact element={<Home/>} />
<Route path="details/:id" element={<ViewNote/>}/>
</Routes>
</BrowserRouter>
and I called it like this in the class component:
import React, { Component } from 'react'
export default class ViewNote extends Component {
componentDidMount(){
console.log(this.props.match.params.id);
}
render() {
return (
<div>
<h2>{this.props.match.params.id}</h2>
</div>
)
}
}
But it shows match undefined in the console!!!
how to solve it??
thanks.

React-Router: Nested route not rendering component

This is a simplified reproduction of the problem: The child with the nested URL does not render.
My file structure is basically this:
-App
--Home
--Pageone
---Childone
I can render Home or Pageone from App, then I can render Home or Pageone from Pageone or Home respectively, but I cannot render Childone from its 'parent page' Pageone. I am not quite sure what is done wrong.
The code is shared below, and this sandbox
App.jsx
import { BrowserRouter, Switch, Route } from "react-router-dom";
import Pageone from "./Pageone";
import Home from "./Home";
export default function App() {
return (
<BrowserRouter>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route exact path="/pageone">
<Pageone />
</Route>
</Switch>
</BrowserRouter>
);
}
Home.jsx
import { Link } from "react-router-dom";
const Home = () => {
return (
<div>
<p>This is HOME!</p>
<Link to="/pageone">Pageone</Link>
</div>
);
};
export default Home;
Pageone.jsx
import { Link, Route, useRouteMatch } from "react-router-dom";
import Childone from "./Childone";
const Pageone = () => {
const { path, url } = useRouteMatch();
return (
<div>
<Route exact path={path}>
<PageoneContent url={url} />
</Route>
<Route exact path={path + "/childone"}>
<Childone />
</Route>
</div>
);
};
const PageoneContent = (props) => {
return (
<div>
<p>This is pageone!</p>
<Link to="/">Go back Home</Link>
<br />
<Link to={props.url + "/childone"}>Go to Child One</Link>
</div>
);
};
export default Pageone;
Childone.jsx
import { Link } from "react-router-dom";
const Childone = () => {
return (
<div>
<p>This is Child one!</p>
<Link to="/">Go back Home</Link>
</div>
);
};
export default Childone;
As far as I know you need to use another Switch for routes, otherwise react will have no idea how to match that route path.
<div>
<Route exact path={path}>
Should be:
<Switch>
<Route exact path={path}>

Getting React Props after sending it from Route

I Am Sending React Component from a route as mention in this Link
<Route path='/StartCompaign' render={(props) => <CampaignStart {...props} isDashboard={true} /> } />
and i am getting props in another Component like
{props.childern.render.isDashboard ? <Header /> : "NO" }
APP.JSX file
import React from 'react';
import { Route, Switch } from 'react-router';
import Layout from './components/Layout';
import Home from './components/Dynamic/Home';
import Filter from './components/Dynamic/Filter';
import { AboutCampaign } from './components/Dynamic/AboutCampaign';
import { CampaignStart } from './components/Dynamic/CompaignStart';
import NotFound from './NotFound';
import {SignUp} from './components/Static/SignUp';
import { Login } from './components/Static/Login';
import Dashboard from './components/Dashboard'
import { withCookies } from 'react-cookie';
class App extends React.Component {
render() {
return (
<Switch>
<Layout>
<Route exact path='/' component={Home} />
<Route path='/filter' component={Filter}/>
<Route path='/Campaign/:campaignId' component={AboutCampaign}/>
<Route path='/SignUp' component={SignUp}/>
<Route path='/Login' component={Login}/>
<Route path='/Dashboard' render={(props) => <Dashboard {...props} isDashboard={true} /> } />
<Route path="" component={NotFound} />
</Layout>
</Switch>
);
}
}
export default withCookies(App);
Layout.JSX
import React from 'react';
import { Container } from 'reactstrap';
import Header from './Static/Header';
import Footer from './Static/Footer';
import TopNavigation from './Component/DashBoard/TopNavigation'
export default props => (
<div>
{props.isDashboard ? <Header /> : <TopNavigation /> }
<Container>
{props.children}
</Container>
<Footer />
</div>
);
I am trying to change the <Header/> and <TopNavigation /> in react application when the specfic route is called but props.isDashboard seemed undefined
It's because you are sending props to <Dashboard/> component
<Dashboard {...props} isDashboard={true} />
but not to <Layout /> component.
If Layout component needs to receive isDashboard props you need to pass it like
<Layout isDashboard={true} />
As Layout is parent component, if child components also needs the props you could always pass those to children easily.

react router slug compared to part of array

I started to experiment with react router, and dynamic matches.
I wanted to create a function which matches the slug of the URL to a slug in a JSON file.
The error I get:
TypeError: Unable to get property 'slug' of undefined or null reference
I think that the 'Slug' of the url is undefined, but I am not sure on how to fix it.
screenshot of error
my code for routes.js:
import React from 'react';
import Header from './components/header/header.js';
import Home from './components/home/home.js';
import About from './components/about/about.js';
import NotFound from './components/notFound/notFound.js'
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import PostPage from './components/postpage/postpage.js'
import posts from './files/data.json';
class Routes extends React.Component {
render(){
return (
<Router>
<div>
<Header />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Route path="/:slug" component={props => {
const postt = posts.posts.filter (post => props.params.slug === post.slug)
console.log(postt.length)
return <PostPage post={postt} />
} } />
}}/>
<Route component={NotFound} />
</Switch>
</div>
</Router>
);
}
}
export default Routes;
PostsPage.js:
import React from 'react';
import Post from '../post/post.js'
const PostPage = (props) => (
<div>
<Post {...props.post}/>
</div>
);
export default PostPage;
and posts.js:
import React from 'react';
import { Link } from 'react-router-dom';
import './post.css';
class Post extends React.Component {
render(){
return(
<div>
<div >
<h2 className='subTitle'><Link to={`/post/${this.props.slug}`} className='link'>{this.props.title}</Link></h2>
<p className='content'>{this.props.excerpt}</p>
</div>
</div>
);
}
}
export default Post;
If you made it this far thank you for helping
slug variable is given inside match props which you are missing.
<Route path="/:slug" render={props => {
const postt = posts.posts.filter (post => props.match.params.slug === post.slug)
console.log(postt.length)
return <PostPage post={postt} />
} } />
}}/>
Also, do not inline component use a render function instead. From the docs:
When you use component (instead of render or children, below) the
router uses React.createElement to create a new React element from the
given component. That means if you provide an inline function to the
component prop, you would create a new component every render. This
results in the existing component unmounting and the new component
mounting instead of just updating the existing component. When using
an inline function for inline rendering, use the render or the
children prop (below).
https://reacttraining.com/react-router/web/api/Route/render-func
One of the ways you can get this fixed is by using .find() instead of .filter() like this :
const postt = posts.find (post => props.match.params.slug === post.slug)
And then inside your <Router /> make sure to send the rest of {...props} as well :
<Route path="/:slug" component={props => {
const postt = posts.find (post => props.match.params.slug === post.slug)
console.log(postt.length)
return <PostPage post={postt} {...props} />
} } />

React Router v4 - Nesting Routes Issue

I have the following App component.
class App extends React.Component {
constructor() {
super();
this.state = {}
}
// various methods that interact with state defined here
render() {
const Main = () => (
<div className="main-wrapper">
<ListPicker/>
<ListPane/>
</div>
);
const Search = () => (
<div className="search-wrapper">
<ul className="search-results">
<li>Search Results</li>
</ul>
</div>
);
return (
<div className="app-wrapper">
<Title/>
<SearchBar listResults={this.listResults}/>
<Route exact path="/" component={Main}/>
<Route path="/search" component={Search}/>
</div>
)
}
}
Which is rendered in index.js:
import React from 'react';
import { render } from 'react-dom';
import {
BrowserRouter as Router,
Route
} from 'react-router-dom';
import App from './components/App';
const Root = () => {
return (
<Router>
<div>
<Route exact path="/" component={App}/>
</div>
</Router>
)
};
render(<Root/>, document.getElementById('root'));
Towards the bottom of App you can see I'm trying to have either the Main component or Search component render below <Title/> and <SearchBar/> based on the paths / or /search. As far as I can tell from the React-Router docs, I'm doing what's shown in their example app, but I can't get this to work correctly. With this current setup Main renders fine at / but when navigating to /search nothing renders inside of <Root/>. I also tried wrapping those two <Routes/> in a <Switch/> but got the same result. Am I missing something?
You put a exact Route in you index.js. So the route /search can't find a way. So change to:
const Root = () => {
return (
<Router>
<div>
<Route path="/" component={App}/>
</div>
</Router>
)
};

Categories