React js do common header - reactjs

I am new to ReactJS. I need to have a common header and change title according to the route changes. Do I need to create a header.jsx file and import it? Or else, how can I render the header (common file) with route?
My routing part looks like this:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.jsx';
import Home from './Home.jsx';
import { Router, Route, Link, browserHistory, IndexRoute } from 'react-router';
ReactDOM.render((
<Router history = {browserHistory}>
<Route path = "/home" component = {Home} />
<Route path = "/" component = {App}>
</Route>
</Router>
));

This should work:
header.jsx:
class Header extends Component {
render() {
return (<div>Your header</div>);
}
}
first-page.jsx:
class FirstPage extends Component {
render() {
return (<div>First page body</div>);
}
}
second-page.jsx
class SecondPage extends Component {
render() {
return (<div>Second page body</div>);
}
}
app.jsx:
import Header from './header.jsx';
class App extends Component {
render() {
return (
<div>
<Header />
{this.props.children}
</div>
);
}
}
web-app.jsx:
import App from './app.jsx';
import FirstPage from './first-page.jsx';
import SecondPage from './second-page.jsx';
ReactDOM.render(
<Router history = {browserHistory}>
<Route path = "/" component = {App}>
<Route path = "/first" component = {FirstPage}>
<Route path = "/second" component = {SecondPage}>
</Route>
</Router>
);

try this https://www.npmjs.com/package/react-helmet
import React from "react";
import Helmet from "react-helmet";
export default function Application () {
return (
<div className="application">
<Helmet title="My Title" />
...
</div>
);};

So if you need to display a common header among your routes, there's a couple ways of doing it. One is you can define your header inside its own component. Something simple for example:
import React from 'react';
export default React.createClass({
render() {
return <div className='header'><h1>{this.props.title}</h1></div>;
}
}
Then in your home component, app component, etc. Simply put inside your render(), after importing it at the top of each file.
The other option is to create your own sort of container component, still using the Header component we defined above:
import React from 'react';
export default React.createClass({
render() {
return (
<div className='container'>
<Header title={this.props.title} />
{this.props.children}
</div>
);
}
}
Then where you declare your routes:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.jsx';
import Home from './Home.jsx';
import Container from './Container.jsx';
import { Router, Route, Link, browserHistory, IndexRoute } from 'react-router';
ReactDOM.render((
<Router history = {browserHistory}>
<Route path = "/home" component = {<Container title='home'><Home /></Container>} />
<Route path = "/" component = {<Container title='app'><App /></Container>}>
</Route>
</Router>
));
Admittedly i have not tried that second option. You might have to pass the router as a parameter from the container component down to its use of children component, if you want to do things like router.transitionTo('/path').
It's just an option if you don't want to repeat everywhere.

Related

ReactJS - React Router not changing component but url is changing

I am rookie to ReactJS and recently start learning. I've created 2 components home and ContactList using TSX. I am using React-Router to change route.
App.JS
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import { Header } from "./Grid/header";
import { Footer } from "./Grid/footer";
import { Menulink } from './Grid/Menulinks';
import { Home } from './Grid/Home';
import { ContactList } from './Grid/ContactList';
class App extends Component {
render() {
return (
<div>
<Header title="This is Header">
</Header>
<Menulink></Menulink>
<Router>
<switch>
<Route exact path="/" component={Home} />
<Route path="/contact" component={ContactList} />
</switch>
</Router>
<Footer></Footer>
</div>
)
}
}
export default App;
Menulink.tsx:
import * as React from 'react';
import { Link, BrowserRouter as Router } from "react-router-dom";
export class Menulink extends React.Component {
render() {
return (
<Router>
<switch>
<Link to="/">Home </Link> |
<Link to="/contact">Contact List</Link>
</switch>
</Router>
)
}
}
Issue is, when I click on link, URL change, but component is not
getting replace. is it because I've written links and route both in
different files?
First, you need to have one Router instance
Second, MenuLink needs to be rendered as a Child of Router
Third, import Switch from react-router-dom
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import { Header } from "./Grid/header";
import { Footer } from "./Grid/footer";
import { Menulink } from './Grid/Menulinks';
import { Home } from './Grid/Home';
import { ContactList } from './Grid/ContactList';
class App extends Component {
render() {
return (
<div>
<Header title="This is Header">
</Header>
<Router>
<Route component={Menulink} />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/contact" component={ContactList} />
</Switch>
</Router>
<Footer></Footer>
</div>
)
}
}
export default App;
import * as React from 'react';
import { Link, BrowserRouter as Router } from "react-router-dom";
export class Menulink extends React.Component {
render() {
return (
<React.Fragment>
<Link to="/">Home </Link> |
<Link to="/contact">Contact List</Link>
</React.Fragment>
)
}
}
This is because you have two different Router instances. You need only One router instance at the Top of the component heirarchy. Or at the very least..the heirarchy that you expect to be changing with URLs.
So if you put your <MenuLink /> under the <Router> that is defining the routes, your routing will work fine.

How to change the URL and content without refresh website using reactJS?

I came across the site https://hashnode.com/. When we click any topic it updates the URL and content without refreshing the site.
I know we can update the content using states and props without refresh.
How to change the URL at the same time?
Image
That's what React Router is for.
Routes.js
import React from 'react';
import {BrowserRouter,Switch,Route, withRouter} from 'react-router-dom';
import FirstPage from './pages/FirstPage';
import SecondPage from './pages/SecondPage';
class Routes extends React.Component {
render() {
return(
<Switch>
<Route exact path="/page-1" component={FirstPage} />
<Route exact path="/page-2" component={SecondPage} />
</Switch>
)
}
}
App.js
import React from 'react';
import store from "./Store";
import { Provider } from 'react-redux';
import Routes from "./Routes";
import {BrowserRouter} from 'react-router-dom';
class App extends React.Component
{
render()
{
return (
<Provider store={store}>
<BrowserRouter>
<Routes/>
</BrowserRouter>
</Provider>
)
}
}
export default App;

Nesting relative routes with react-router

I have a categories index page which links to a products index page of products specific to that category. That much is functioning. But when I attempt to click on a product linked to a show component specific to that product I'm encountering trouble. Below is my code:
router.js
import React from 'react';
import { Router, Route, Switch } from 'react-router';
import createBrowserHistory from 'history/createBrowserHistory'
import App from './App';
import CategoriesIndexPage from './pages/categories/CategoriesIndexPage';
import ProductsIndexPage from './pages/products/ProductsIndexPage';
import ProductShow from './pages/products/ProductShow';
import LocationsPage from './pages/LocationsPage';
const history = createBrowserHistory()
const router = (
<Router history={history}>
<Switch>
<Route exact path='/' component={App}/>
<Route path='/categories' component={CategoriesIndexPage}/>
<Route path='/locations' component={LocationsPage}/>
<Route path='/:category' component={ProductsIndexPage}>
<Route path='/:id' component={ProductShow}/>
</Route>
</Switch>
</Router>
);
export default router;
ProductIndexPage.js
import React, { Component } from 'react';
import { BWReactData } from '../../config/FirebaseConstants.js';
import Head from '../../components/Head.js';
import Foot from '../../components/Foot.js';
import ProductsIteration from './ProductsIteration';
class ProductsIndexPage extends Component {
constructor(props){
super(props);
this.state = {
allProducts: [],
loading: true,
}
}
componentDidMount() {
...
}
render() {
let allProducts = this.state.allProducts;
let loading = this.state.loading;
let categoryURL = this.props.location.state.category;
return (
<div>
<Head/>
<ProductsIteration
allProducts={allProducts}
loading={loading}
categoryURL={categoryURL}
/>
<Foot/>
</div>
)
}
}
export default ProductsIndexPage;
ProductsIteration.js
import React from 'react';
import { Link } from 'react-router-dom';
import { Col, Row } from 'react-materialize';
const ProductsIteration = props => {
let category = props.categoryURL;
if (props.loading) {
return <div>Loading...</div>
}
return (
<Row>
{props.allProducts.map(function(object) {
return (
<Col s={12} m={6} l={3} key ={object.id}>
<div style={styles.wrapper}>
<Link to={{ pathname: `${category}/${object.id}`, state: { id: object.id }}}>
<img src={object.img} style={styles.image} />
<div style={styles.description}>
<div style={styles.descriptionContent}>{object.name}</div>
</div>
</Link>
</div>
</Col>
)
})}
</Row>
)
}
export default ProductsIteration;
The link within my iteration component renders the '/:category/:id' url in my navbar but the page does nothing. This is my first project using router and any guidance would be much appreciated.
In React Router v4:
Router components are imported from 'react-router-dom' rather than 'react-router'.
The traditional <Router/> component has been replaced with the <BrowserRouter/> component, which requires no props.
Nesting routes is no longer convention. Instead, you'll have to nest your <ProductShow/> as a component prop of a <Route/> component within a <Switch/> component within your <ProductIndexPage/> component.
See below for an example.
Router.js:
// React.
import React from 'react'
// React Router DOM.
import {
BrowserRouter as Router,
Route,
Switch
} from 'react-router-dom'
// Routes.
import App from './App'
import CategoriesIndexPage from './pages/categories/CategoriesIndexPage'
import ProductsIndexPage from './pages/products/ProductsIndexPage'
import LocationsPage from './pages/LocationsPage'
// Router.
const Router = (
<Router>
<Switch>
<Route exact path='/' component={App}/>
<Route path='/categories' component={CategoriesIndexPage}/>
<Route path='/locations' component={LocationsPage}/>
<Route path='/:category/:id?' component={ProductsIndexPage}/>
</Switch>
</Router>
)
// Export.
export default Router
ProductIndexPage.js:
// React.
import React from 'react'
// BW React Data.
import {
BWReactData
} from '../../config/FirebaseConstants.js'
// Head.
import Head from '../../components/Head.js'
// Foot.
import Foot from '../../components/Foot.js'
// Products Iteration.
import ProductsIteration from './ProductsIteration'
// Product Show.
import ProductShow from './ProductShow'
// React Router DOM.
import {
Switch
} from 'react-router-dom'
// Products Index Page.
class ProductsIndexPage extends React.Component {
// Constructor.
constructor(props){
// Super Props.
super(props)
// State.
this.state = {
allProducts: [],
loading: true,
}
}
// Did Mount.
componentDidMount() {
...
}
// Render.
render() {
let allProducts = this.state.allProducts
let loading = this.state.loading
let categoryURL = this.props.location.state.category
return (
<div>
<Head/>
<ProductsIteration
allProducts={allProducts}
loading={loading}
categoryURL={categoryURL}
/>
{this.props.match.params.id ? (<ProductShow/>) : ''}
<Foot/>
</div>
)
}
}

Reactjs: returning children with cloneElement

I'm new to this and following a tutorial. I've actually copied the code from the starter files but the children do now show in the React devtools, hence not rendering. The components are fine and I can render them individually. PhotoGrid doesn't show as a child of Main that's all. This is the code:
Main.js
import React from 'react';
import { Link } from 'react-router';
const Main = React.createClass({
render() {
const props = this.props;
return (
<div>
<h1>
<Link to="/">Reduxstagram</Link>
</h1>
{ React.cloneElement(props.children, props) }
</div>
);
}
});
export default Main;
App.js
import React from 'react';
import { render } from 'react-dom';
// Import css
import css from './styles/style.styl';
// Import Components
import Main from './components/Main';
import Single from './components/Single';
import PhotoGrid from './components/PhotoGrid';
// import react router deps
import { Router, Route, IndexRoute, browserHistory } from 'react-router';
render(
<Router history={browserHistory}>
<Route path="/" component={Main}>
<IndexRoute component={PhotoGrid}></IndexRoute>
<Route path="/view/:postId" component={Single}></Route>
</Route>
</Router>, document.getElementById('root'));
{ props.children } will render the children of the component (from your question I see no need to use React.cloneElement). See modified code below:
const Main = React.createClass({
render() {
const props = this.props;
return (
<div>
<h1>
<Link to="/">Reduxstagram</Link>
</h1>
{ props.children }
</div>
);
}
});
Sidenote
React-router has recently been updated to v4. You may want to use the new router (docs for react-router-4).

React Router not Rendering my Routes in Horizon

I'm working on a simple web app with Horizon and React to learn more about web design.
For some reason, my Router will not Route to various sub directories. For instance, I get my Layout page when I visit localhost:8181/, but when I visit localhost:8181/Home, I get (displayed in the webpage in Firefox) 'File "dist\Home" not found."
I also get this code in the Firefox console:
The character encoding of the plain text document was not declared.
The document will render with garbled text in some browser
configurations if the document contains characters from outside the
US-ASCII range. The character encoding of the file needs to be
declared in the transfer protocol or file needs to use a byte order
mark as an encoding signature.
Here is my Router Code:
//Routing.jsx
import React from 'react'
import { Router, Route, Link, browserHistory, IndexRoute, IndexRedirect } from 'react-router'
//Routes:
import MainLayout from './components/MainLayout.jsx'
import Search from './components/Search.jsx'
import PickFilm from './components/PickFilm.jsx'
import Login from './components/Login.jsx'
import Home from './components/Home.jsx'
export const Routing = () => {
return (
<Router history={browserHistory}>
<Route path = "/" component = {MainLayout} >
<Route path = "/Home" component = {Home} />
<Route path = "/Search" component = {Search} />
<Route path = "/PickFilm" component = {PickFilm} />
</Route>
<Route path = "/Login" component = {Login} />
</Router>
)
}
Here is my Index code:
//Index.jsx
import React from 'react'
import ReactDOM from 'react-dom'
import { Routing } from './Routing.jsx'
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
// Routing Information
ReactDOM.render((
<MuiThemeProvider>
<Routing />
</MuiThemeProvider>
), document.getElementById('root'));
Here is my component for Home:
//components/Home.jsx
import React, { Component } from 'react'
export default class Home extends Component {
render() {
return (
<span>You're home.</span>
)
}
}
Here is my component for the Layout:
//components/MainLayout.jsx
import React, { Component } from 'react'
import Navbar from './Navbar.jsx'
//Needed for onTouchTap
//http://stackoverflow.com/a/34015469/988941
import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin();
export default class MainLayout extends Component {
render() {
return(
<div>
<Navbar />
</div>
);
}
}
Like I said, the layout will render when visiting localhost:8181/. But I get that error when visiting any of the subcomponents, such as localhost:8181/Home. Where am I going wrong?
I'm using these software versions:
babel-core: 6.10.4 (+ plugins and presets for react & es2015),
webpack 1.13.1,
Horizon 1.1.3,
material-ui 0.15.2,
React 15.2.1,
React-router 2.5.2.
You forgot to include {this.props.children} inside the render method of MainLayout so your child routes aren't being rendered at all.

Resources