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>
)
}
};
Related
If I type anything in my http://localhost:3000/anything it will do the same as if I type home or / or login, nothing. The page will be blank.
My social.js:
import React, { Component } from 'react';
import { Route, Switch } from 'react-router-dom';
import Home from '../../containers/Pages/Home/Home';
import Login from '../../containers/Pages/Login/Login';
class Social extends Component {
render () {
return (
<div>
<Switch>
<Route path="/home" exact component={Home} />
<Route path="/login" exact component={Login} />
</Switch>
</div>
);
}
}
export default Social;
app.js:
import React, { Component } from 'react';
import { BrowserRouter } from 'react-router-dom';
import Layout from './Layout/Layout'
import Social from './containers/Pages/Social';
class App extends Component {
render() {
return (
<BrowserRouter>
<div className="App">
<Layout>
<Social />
</Layout>
</div>
</BrowserRouter>
);
}
}
export default App;
Any ideas what is wrong?
Thanks.
----- Edit, I notice when I remove <Layout> ... </Layout> from app.js it works.
my Layout.js:
import React, { Component } from 'react';
import Toolbar from '../components/Navigation/Toolbar/Toolbar';
class Layout extends Component {
render() {
return (
<>
<Toolbar />
</>
);
}
}
export default Layout;
and Toolbar:
import React, { Component } from 'react';
import classes from './Toolbar.module.css';
class toolbar extends Component {
render() {
return(
<>
<header className={classes.Toolbar}>
toolbar
</header>
</>
);
}
}
export default toolbar;
I think you missing the wrapping element around Toolbar component
import React, { Component } from 'react';
import Toolbar from '../components/Navigation/Toolbar/Toolbar';
class Layout extends Component {
render() {
return (
<div>
<Toolbar />
<div>
);
}
}
export default Layout;
same with the Toolbar. should be as follows:
import React, { Component } from 'react';
import classes from './Toolbar.module.css';
class Toolbar extends Component {
render() {
return(
<div>
<header className={classes.Toolbar}>
toolbar
</header>
</div>
);
}
}
export default Toolbar;
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:
I want to change innerHTML of a div, when I click on the button. I don't know why, but instead of getting an error, or getting the expected result it deletes to content and replacing it with "[object Object]".
How can I get it work?
import React from 'react';
import Login from './components/login.js';
import SignIn from './components/signin';
import './App.css';
function App() {
function LoginOnClick(){
document.getElementById("wrapper").innerHTML = <SignIn />;
}
return (
<div className="container" id="wrapper">
<button onClick={LoginOnClick}>Login</button>
<Login />
</div>
);
}
export default App;
You can make use of Hooks (Added n React 16.8).
import React, {useState} from 'react';
import Login from './components/login.js';
import SignIn from './components/signin';
import './App.css';
function App() {
const [signIn, setSignIn] = useState(false);
return (
<div className="container" id="wrapper">
{signIn ? <SignIn /> : <> //This is React Fragments syntax
<button onClick={() => setSignIn(true)}>Login</button>
<Login />
</>
}
</div>
);
}
export default App;
With react you don’t have to set the innerHtml to do this, instead the more typical way is to have internal state in your component and conditionally render your SignIn component based off that. To use state the component either needs to be class or use hooks, classes are more traditional so I changed the component to be a class.
To make a class a react component you need to extend the class with the React.Component, this is because react components have lots of internal behaviours that you need to include with your class for it to be considered a component.
So
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
signIn: false,
};
this.LoginOnClick = () => {
this.setState({ signIn: true });
};
}
render() {
if (this.state.signIn) {
return (
<div className="container">
<SignIn />
</div>
);
}
return (
<div className=“container”>
<button onClick={this.LoginOnClick}>Login</button>
<Login />
</div>
);
}
}
Here is a simple way to do it:
import {useState} from "react";
const App = () => {
const [txt, setTxt] = useState("");
setTxt(<p> 'Lorem ipsum dummy text blabla.' </p>);
return(
<div>
{txt}
</div>
)
}
export default App;
I have the following React example, and I'm trying to show a success toast (from mdbootstrap library) every time the isShowing state is true. This works as expected regarding the toast, but a number is displayed next to the button, and increments after each click. This number also appears as a children of the main div from the App file ( See attached image and codesandbox link) .
Thanks in advance!
import React, { Component } from "react";
import Nav from "./Navbar";
import Routes from "./Routes";
import Mes from "./Message";
import { Button, toast } from "mdbreact";
import "./App.css";
class App extends Component {
state = {
isShowing: false
};
handleClick = () => {
this.setState({
isShowing: true
});
};
render() {
return (
<div className="App">
<Mes />
<Button color="primary" onClick={this.handleClick}>
show Alert{" "}
</Button>
{this.state.isShowing ? toast.success("Success message") : ""}
<Routes />
</div>
);
}
}
export default App;
codesandbox link : https://codesandbox.io/s/l2xqplx4rm
You don't need to render toast.success in your code. Remove
{this.state.isShowing ? toast.success("Success message") : ""}
In above code case your binding the toast's toast.success methods response which is nothing but the active toast length. So its displaying number over there.
Just below code is enough to show toast on button click.
import React, { Component } from "react";
import Nav from "./Navbar";
import Routes from "./Routes";
import Mes from "./Message";
import { Button, toast } from "mdbreact";
import "./App.css";
class App extends Component {
handleClick = () => {
//show toast
toast.success("Success message");
};
render() {
return (
<div className="App">
<Mes />
<Button color="primary" onClick={this.handleClick}>
Show Alert
</Button>
<Routes />
</div>
);
}
}
export default App;
Here is updated code
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>
)
}
}