Reveal a navigation component on one route in React - javascript

I have an app with navigation at the top (Home, About, Faq). Only on HOME route I need the menu to be hidden and then reveal onscroll. Navigation is built in App.jsx so it appears on every single page. How do I enable the reveal for just this particular route?
My reveal component
import React, { Component } from 'react';
class NavScroll extends React.Component {
constructor(props){
super(props);
this.state={isHide:false};
this.hideBar = this.hideBar.bind(this)
}
hideBar(){
let {isHide} = this.state
window.scrollY > this.prev?
!isHide && this.setState({isHide:true})
:
isHide && this.setState({isHide:false})
this.prev = window.scrollY;
}
componentDidMount(){
window.addEventListener('scroll',this.hideBar);
}
componentWillUnmount(){
window.removeEventListener('scroll',this.hideBar);
}
render(){
let classHide=this.state.isHide?"hide":""
return <div className={"fixed "+classHide}>
</div>;
}
}
export default NavScroll;
App.jsx
import React, { Component } from 'react';
import NavLink from './global/NavLink.jsx';
import Footer from './global/Footer.jsx';
import NavScroll from './global/NavScroll.jsx';
var App = React.createClass({
render: function(){
return (
<div>
<div>
<NavLink to="/"><img className="logo" alt="HOME"></img></NavLink>
<NavLink to="/about" className="navMenuButton">ABOUT</NavLink>
<NavLink to="/faq" className="navMenuButton">FAQ</NavLink>
</div>
{ this.props.children }
<Footer />
</div>
);
}
});
export default App;

You'll want to check the pathname of the current location. The location is an injected prop of the component rendered for a matched route.
class App extends React.Component {
render() {
const { location } = this.props
return (
<div>
{ location.pathname === '/' ? <HomeNavigation /> : <OtherNavigation /> }
</div>
)
}
}

Related

How can I do to hide my div using react with components?

I have this code for the App :
import React, {Component} from 'react';
import App1 from './App1';
class App extends Component {
render(){
return (
<>
<App1/>
<div>
<h1>Hello</h1>
</div>
</>
);
}
}
export default App;
And this code is for the App1
import React, {Component} from 'react';
class App1 extends Component {
render() {
return (
<>
<button>Hide</button>
</>
);
}
}
export default App1;
I would like when I click on the Button to hide my div which displays "Hello". But I have no idea to do this ?
Could you help me please ?
Thank you very much !
You can hide the div in the parent component i.e (App.js) by using props. So here are the steps you need to follow:
create a function named as handleHide in App component, and pass it as a prop to App1 component.
Define a state named as hide in App component and pass it as a prop in App1 component.
Inside App1 component use the hide prop to change the text of button(it's bonus).
Assign handleHide function passed as prop from App to App1 component's button element's onClick .
Here are the files:
App.js
import React, { Component } from "react";
import App1 from "./App1";
class App extends Component {
state = {
hide: false
};
handleHide = () => {
this.setState({ hide: !this.state.hide });
};
render() {
return (
<>
<App1 handleHide={this.handleHide} hide={this.state.hide} />
<div>{!this.state.hide && <h1>Hello</h1>}</div>
</>
);
}
}
export default App;
And App1.js will be:
import React, { Component } from "react";
class App1 extends Component {
render() {
return (
<>
<button onClick={this.props.handleHide}>
{this.props.hide ? "Show" : "Hide"}
</button>
</>
);
}
}
export default App1;
You can see the full working code here.
Using class component is perfectly fine. You can use functional component to use react hooks it makes your code more readable and less code.
App.js
import React, { useState } from "react";
import App1 from "./App1";
export default function App() {
const [show, setShow] = useState(true);
return (
<>
<App1 setShow={setShow} show={show} />
<div>{show && <h1>Hello</h1>}</div>
</>
);
}
App1.js
import React from "react";
export default function App1({ setShow, show }) {
return (
<>
<button onClick={() => setShow(!show)}>{show ? "Hide" : "Show"}</button>
</>
);
}
You create a state in App.js and pass those state down to App1.js, which look like this
class App extends Component {
constructor(){
super();
this.state = {
hidden: false
};
this.changeHiddenStatus = this.changeHiddenStatus.bind(this)
}
changeHiddenStatus = () => {
this.setState(state => ({
hidden: !state.hidden
}))
}
render(){
return (
<>
<App1 handleClick={this.changeHiddenStatus}/>
<div>
<h1>Hello</h1>
</div>
</>
);
}
}
And then in the App1.js you did this
class App1 extends Component {
render() {
return (
<>
<button onClick={props.handleClick}>Hide</button>
</>
);
}
}
These are some basic React stuff, so if you don't get it I suggest you should read the React doc again.

Passing data from child to parent component not working in react

I am passing data from my child component (Header component) to my parent component (App component). My idea: when I click on my creating button in header component I want to send information to app component to hide header and footer. Here is code example.
Header.jsx:
import React, { Component } from 'react';
import { Nav, Navbar, Button } from "react-bootstrap";
class Header extends Component {
constructor(props) {
super();
this.state = {
showHeaderAndFooter: false
};
}
onChangeChildComponent = () => {
this.props.changeVisibilityOfHeaderAndFooter(this.state.showHeaderAndFooter);
}
render() {
return (
<Navbar bg="dark" variant="dark">
<Nav className="mr-auto">
<Button href="/createGym" onClick={this.onChangeChildComponent.bind(this)}> Create </Button>
</Nav>
</Navbar>
);
}
}
export default Header;
App.js:
import React, { Component, Fragment } from 'react';
import './App.css';
import './components/header';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import Header from './components/header';
import Footer from './components/footer';
import Home from './components/home';
import CreateGym from './components/create-gym';
import Login from './components/authentication/login';
class App extends Component {
constructor() {
super();
this.state = {
showHeaderAndFooter: true
};
}
onChangeChildComponent (showHeaderAndFooter) {
this.setState(
{
showHeaderAndFooter: showHeaderAndFooter
});
}
Container = () => (
<div>
{ this.state.showHeaderAndFooter &&
<Header
changeVisibilityOfHeaderAndFooter = {this.onChangeChildComponent.bind(this)}
/>
}
<div className="container">
<Route exact path='/' component={Home} />
<Route path="/createGym" component={CreateGym} />
<Route path="/login" component={Login} />
</div>
{ this.state.showHeaderAndFooter && <Footer /> }
</div>
)
render() {
console.log(this.state.showHeaderAndFooter);
return (
<BrowserRouter>
<Switch>
<Fragment>
{ <Route component={this.Container}/> }
</Fragment>
</Switch>
</BrowserRouter>
);
}
}
export default App;
The problem is because my code is entering App constructor twice. At the first time, everything is fine, but on the second time, this boolean showHeaderAndFooter is again set to true because that is the default value. Any idea how to solve this?
you shouldn't be passing from child > parent. react is uni-directional (that means data can only flow in one way, and that way is downwards)
to achieve this, move the state into the parent
class Parent extends React = {
this.state = { showHeaderAndFooter: false }
functionToToggleShowing = () => {
this.setState({showHeaderAndFooter: !this.state.showHeaderAndFooter})
}
render() {
return(
<Child showHeaderAndFooter={this.state.showHeaderAndFooter} functionToToggleShowing={functionToToggleShowing} />
)
}
}
that is pseduo code but essentially move the state to the parent and pass down the state to the child as well as a way to change that state
React allows passing of control from child to parent by means of props.
Here is the 3-step procedure to make it work:
Step 1: Create a data member in Parent, which manipulates parent state.
Step 2: Send the parent's data member as a prop to the child.
Step 3: In the child, Call the prop sent by parent for responding to an event.
Here is a demonstration of passing control from child to parent, using the above technique:
The example has 2 components -
Parent component is App.jsx
Child component is Header.jsx
Parent has a state-manipulating data member called 'hideHeader'.
Parent passes hideHeader as a prop called onClick to the child.
Child calls the prop sent by parent, in response to its onClick event.
Parent component - App.jsx
import React, { Component } from 'react'
import Header from "./Header";
export default class App extends Component {
constructor() {
super();
this.state = {
showHeader: true
}
}
{/* A state-manipulating data member */}
hideHeader = () => {
this.setState({showHeader: false})
}
render() {
return (
<div>
{/* State-manipulating data member sent as prop to child */}
{ this.state.showHeader &&
<Header onClick={this.hideHeader} />
}
</div>
)
}
}
Child component - Header.jsx
import React, { Component } from "react"
export default class Header extends Component {
render() {
return (
<div>
<h1>Header Demo</h1>
{/* Call the prop sent by parent when button is clicked */}
<button onClick={this.props.onClick}>Hide</button>
</div>
)
}
}
Output:
Before 'Hide' button is clicked:
After 'Hide' button is clicked:

how to change value of Navbar title in react?

I just learn react, and I try make a website with Bootstrap.
Suppose below picture is my web page.
When I browse a link that path is "/project/react" the top left (value of Navbar title is "React"), then I browse a link that path is "/project/bootstrap" I hope the top left (value of Navbar title is "Bootstrap"). Is that possible?
Because I got the title still show "React".
Thank you
//MyPage.js
import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootstrap/dist/css/bootstrap.css';
import React, { Component } from 'react';
import { Switch, Route } from 'react-router-dom';
import MyNavbar from '../components/MyNavbar';
import MyReact from '../components/MyReact';
import MyBootstrap from '../components/MyBootstrap';
let pgName = "My Page"
class MyPage extends Component {
constructor(props) {
super(props);
this.state = {
pageName: pgName
};
}
setPageName = (pageName) => {
pgName = pageName;
}
componentDidMount(){
this.setState({ pageName: pgName });
}
render() {
return (
<div>
<MyNavbar pageTitle={this.state.pageName}/>
<Switch>
<Route path="/project/bootstrap" component={MyBootstrap} render={this.setPageName("Bootstrap")}/>
<Route path="/project/react" component={MyReact} render={this.setPageName("React")}/>
</Switch>
</div>
)
}
};
export default ProjectPage;
//MyNavbar.js
import React from 'react';
import Navbar from 'react-bootstrap/Navbar';
import Nav from 'react-bootstrap/Nav';
import Scrollchor from 'react-scrollchor';
class MyNavbar extends React.Component {
constructor(props) {
super(props);
this.state = {
pageTitle: props.pageTitle
};
}
componentWillReceiveProps(props,state){
this.setState({ pageTitle: props.pageTitle });
}
render() {
return (
<Navbar bg="dark " expand="lg" fixed="top">
<Navbar.Brand href="#home" className="menu-title">{this.state.projectTitle}</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" position="absolute" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="ml-auto" >
<Scrollchor to="#docs" animate={{ offset: -90, duration: 300 }} className="nav-link">Docs</Scrollchor>
<Scrollchor to="#tutorial" animate={{ offset: -90, duration: 300 }} className="nav-link">Tutorial</Scrollchor>
<Scrollchor to="#blog" animate={{ offset: -90, duration: 300 }} className="nav-link">Blog</Scrollchor>
</Nav>
</Navbar.Collapse>
</Navbar>
);
}
}
export default MyNavbar;
//MyReact.js
import Container from 'react-bootstrap/Container';
import React from 'react';
class MyReact extends React.Component {
render() {
return (
<h1>React</h1>
);
}
}
export default MyReact;
//MyBootstrap.js
import Container from 'react-bootstrap/Container';
import React from 'react';
class MyBootstrap extends React.Component {
render() {
return (
<h1>Bootstrap</h1>
);
}
}
export default MyBootstrap;
You could do something like this.
Pass a callback to the component as a prop
<Route
path="/project/bootstrap"
render={(props) => <MyBootstrap {...props} isAuthed={true} setPageName={this.setPageName.bind(this)} />}
/>
Call the callback when the component is mounted
import Container from 'react-bootstrap/Container';
import React from 'react';
class MyBootstrap extends React.Component {
componentDidMount() {
const { setPageName } = this.props;
if(typeof setPageName === 'function) {
setPageName('Bootstrap');
}
}
render() {
return (
<h1>Bootstrap</h1>
);
}
}
Why calling setPageName in render prop?
according to react document, a render prop is a function prop that a component uses to know what to render.
In this case no need to use render prop just need an onClick function because you just want to change the title of previous rendered Navbar.
Second remember to add setState in your setPageName function, unless DOM would not be aware of state change neither the corresponding props.
Then when you change the pageName state navbar props will react to the change.
<Route path="/project/react" component={MyReact} onClick={() => setPageName (someValue)} />
setPageName = (newPageName) =>{ setState({pageName : newPageName }) }
wish it will help
This may not be correct and is untested, but have you tried this?:
<Route path="/project/bootstrap" component={MyBootstrap} render={() => this.setPageName("Bootstrap")}/>
<Route path="/project/react" component={MyReact} render={() => this.setPageName("React")}/>
I think this is more likely to work, that way your setPageName function is only running on render.

Keep Button on Edge of sidebar

I am in working on a react template, and I want to have a sidebar navigation component. I am struggling with the expanding portion. So when the nav component expands I want the content to shrink and the expand/collapse button to stay on the edge of the menu.
closed
open
My idea was to use react-bootstrap and its Col component, but that did not work. My next idea is to keep track of the width of the sidebar menu and adjust the content and button accordingly. For this idea, I am thinking I need to pull up the width state to my top level component, but that seems sketch. I am trying to figure out how to get the width of a component as it expands and shrinks. My experience is pretty low, this is my first on my own react project.
App.js (top level component)
import React, { Component } from "react";
import { Route, NavLink, HashRouter } from "react-router-dom";
import Home from "./Home";
import SidebarContainer from "./Sidebar/SidebarContainer";
import Row from "react-bootstrap/Row";
export default class App extends Component {
render() {
return (
<HashRouter>
<div>
<Row>
<div className="header">
<span>Company Name</span>
<span>App Name Goes Here</span>
<span>Hello Username</span>
</div>
</Row>
<Row>
<SidebarContainer/>
<div className="content">
<Route exact path="/" component={Home} />
</div>
</Row>
</div>
</HashRouter>
);
}
}
SidebarContainer
import React, { Component } from "react";
import ToggleButton from './ToggleButton';
import SidebarMenu from './SidebarMenu';
export default class SidebarContainer extends Component {
constructor(props) {
super(props);
this.state = {
SidebarOpen: false
};
this.toggleSidebar = this.toggleSidebar.bind(this);
}
toggleSidebar(){
this.setState({
SidebarOpen: !this.state.SidebarOpen
});
}
render(){
return (
<div>
<ToggleButton onClick = {this.toggleSidebar} menuVisibility = {this.state.SidebarOpen}/>
<SidebarMenu menuVisibility = {this.state.SidebarOpen}/>
</div>
)
}
}
Sidebar menu
import React, { Component } from "react";
import "./SidebarMenu.css";
import FeedbackButton from "./FeedbackButton";
export default class SidebarMenu extends Component {
render() {
let visibility = "hide";
if(this.props.menuVisibility){
visibility = "show";
}
return (
<div id="SidebarMenu" className= {visibility}>
<h2>Home</h2>
<h2>About</h2>
<h2>Contact</h2>
<h2>Search</h2>
<FeedbackButton/>
</div>
)
}
};
Button
import React, { Component } from "react";
import "./ToggleButton.css"
export default class ToggleButton extends Component {
render() {
let menuStatus = "hidden";
let direction = ">"
if(this.props.menuVisibility){
menuStatus = "open"
direction = "<"
}
return (
<button id="toggleButton" className={menuStatus} onClick={this.props.onClick}> {direction} </button>
)
}
};

Using react api context alongside react router

I have a problem with passing context to route. I get an error when i click a link that goes to my component where context was passed from App component. Below is that component with App (only one import just to show where Context is coming from):
App.js
import { Context } from './Context';
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
cryptolist: []
}
}
componentDidMount = () => {
fetch('https://api.coinmarketcap.com/v2/ticker/?structure=array')
.then(response => response.json())
.then(json => this.setState({
cryptolist: json.data
}))
}
render() {
return (
<div>
<Menu />
<Context.Provider value={this.state}>
<Userlist />
</Context.Provider>
</div>
)
}
}
export default App;
Userlist.js ( should be cryptolist or something )
import { Context } from '.././Context'
export default class Userlist extends Component {
render() {
return (
<main>
<Context.Consumer>
{(context) => context.cryptolist.map(el => {
return (
<div>
<h2>{el.name}</h2>
<h5>{el.symbol}</h5>
<h3>{el.quotes.USD.price}</h3>
</div>
)
})}
</Context.Consumer>
</main>
)
}
}
Context.js
import React from 'react';
export const Context = React.createContext();
Everything works just fine here untill i wanted to make a menu that links to this component.
import React from "react";
import { slide as Slider } from 'react-burger-menu';
import { BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
import Main from './main';
import Userlist from './userlist';
export default class Menu extends React.Component {
render () {
return (
<Router>
<div className="bg-navy w-100 h-100">
<Slider width={ 180 } isOpen={ false }>
<Link className="menu-item" to="/main">Home</Link>
<Link className="menu-item" to="/crypto">About</Link>
</Slider>
<Switch>
<Route path="/main" component={Main} />
<Route path="/crypto" component={Userlist} />
</Switch>
</div>
</Router>
);
}
}
When i click a link to component Userlist i get an error thats cryptolist is not defined. I get it that Userlist can't see a context after clicking link to it. How to pass it correctly?
You are using the routes in the Menu component. Is this really you want? Though, I don't know how this slide thingy works. Maybe this is the way you want to go. I think your problem occurs because your Menu component is not wrapped by the provider. Try like this:
<Context.Provider value={this.state}>
<Menu />
<Userlist />
</Context.Provider
Your Menu component will call Userlist but as it is out the Provider the context doesn’t exist!
Replace Userlist in Context.Provider by Menu and all will be fine.

Categories

Resources