ReactJS OnClick render - reactjs

I am new to ReactJS and I am trying to make a menu that by pressing any of the functions the active class will disappear and the new page will appear. In here for instance, I am trying to click on My Order and get forwarded to the page I asked to load. How do I make this correctly? Here is my current code:
import React from 'react';
import ReactDOM from 'react-dom';
import "./index.css";
class MainPanel extends React.Component {
render() {
return (
<div className="main-layout">
<header>
<ul className="top">
<h1>Header</h1>
</ul>
</header>
<ul className="categories">
<li>Main Panel</li>
<li onClick={<MyOrder />}>My Order</li>
<li>Technical Support</li>
<li>My Payments</li>
<li>Suggestions/ Questions</li>
</ul>
</div>
);
}
}
function MyOrder () {
return (
<div className="main-layout">
<header>
<ul className="top">
<h1>My Order</h1>
</ul>
</header>
<ul className="categories">
<li>Where is my order?</li>
<li>My order delays more than the expected time</li>
<li>My order status shows that the order arrived but it did not</li>
<li>I have a complaint</li>
<li>Suggestions/ Questions</li>
</ul>
</div>
);
}
ReactDOM.render(
<MainPanel />,
document.getElementById('root')
);

Without React Router and other 3rd party libraries you could do something like this:
class Overview extends React.Component {
onMenuClick(id) {
return this.props.onMenuClick(id);
}
render() {
return(
<ul className="categories">
<li onClick={this.onMenuClick.bind(this, "mainPanel")}>Main Panel</li>
<li onClick={this.onMenuClick.bind(this, "myOrder")}>My Order</li>
<li onClick={this.onMenuClick.bind(this, "technicalSupport")}>Technical Support</li>
<li onClick={this.onMenuClick.bind(this, "myPayments")}>My Payments</li>
<li onClick={this.onMenuClick.bind(this, "suggestions")}>Suggestions/ Questions</li>
</ul>
);
}
}
class MainPanel extends React.Component {
// sets the initial value for this.state.page
componentWillMount() {
this.setState({
page: "overview"
});
}
switchPage(id) {
this.setState({ page: id });
}
showComponent() {
if(this.state.page === "overview") return (<Overview
onMenuClick={::this.switchPage}
/>);
if(this.state.page === "myOrder") return <MyOrder />;
throw new Error(`${this.state.page} is not a valid page id`);
}
render() {
return (
<div className="main-layout">
<header>
<ul className="top">
<h1>Header</h1>
</ul>
</header>
{ this.showComponent() }
</div>
);
}
}
You change the view by updating the state. Depending on the state different components are mounted/unmounted.
Note based on my experience: Try to handle your app state (in our case the current page information) via React Baobab or something like this (centralized state) because otherwise all these props bubblings become confusing.

Related

How to make Hamburger Icon menu function to work with single click in React.js?

I have been following a coding tutorial of making responsive Navbar from Youtube in Html,CSS and JS. While i really wanted to remake it again in react, the hamburger icon works flawlessly previously when i made it in plain Html, CSS and JS Click here to see the example. (Switch the browser in mobile view to see the Hamburger icon)
But when I copied all my code in react (as follows):
import React, { Component } from "react";
import "./style/navbar.css";
import { Link } from "react-router-dom";
class navbar extends Component {
render() {
const navslide = () => {
const burger = document.querySelector(".burger");
const nav = document.querySelector(".nav-links");
const navLinks = document.querySelectorAll(".nav-links li");
burger.addEventListener("click", () => {
nav.classList.toggle("nav-active");
navLinks.forEach((link, index) => {
if (link.style.animation) {
link.style.animation = "";
} else {
link.style.animation = `navLinkFade 0.5s ease forwards ${index / 7 +
0.5}s`;
}
});
burger.classList.toggle("toggle");
});
};
return (
<div>
<nav>
<div className="logo">
<h3>College Facemash</h3>
</div>
<ul className="nav-links">
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/login">Login / Signup</Link>
</li>
</ul>
<div className="burger" onClickCapture={navslide}>
<div className="line1"></div>
<div className="line2"></div>
<div className="line3"></div>
</div>
</nav>
</div>
);
}
}
export default navbar;
it worked well but not not functioning in single click. Instead it did required Double click to function.
Click here to see the demo.(Switch the browser in mobile view to see the Hamburger icon)
So, What changes should i made in order to make my code work flawlessly
Your help would be really valuable to me.
Thanks...
Try like this:
class Navbar extends Component {
const navslide = () => {
const nav = document.querySelector(".nav-links");
const navLinks = document.querySelectorAll(".nav-links li");
nav.classList.toggle("nav-active");
navLinks.forEach((link, index) => {
if (link.style.animation) {
link.style.animation = "";
} else {
link.style.animation = `navLinkFade 0.5s ease forwards ${index / 7 + 0.5}s`;
}
});
burger.classList.toggle("toggle");
});
};
render() {
return (
<div>
<nav>
<div className="logo">
<h3>College Facemash</h3>
</div>
<ul className="nav-links">
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/login">Login / Signup</Link>
</li>
</ul>
<div className="burger" onClick={() => navslide()}>
<div className="line1"></div>
<div className="line2"></div>
<div className="line3"></div>
</div>
</nav>
</div>
);
}
}
why calling burger.addEventListener("click") while your function will run on burger click! this is why it need 2 click to run!
import React, { Component } from "react";
import "./style/navbar.css";
import { Link } from "react-router-dom";
class navbar extends Component {
render() {
const navslide = () => {
const burger = document.querySelector(".burger");
const nav = document.querySelector(".nav-links");
const navLinks = document.querySelectorAll(".nav-links li");
nav.classList.toggle("nav-active");
navLinks.forEach((link, index) => {
if (link.style.animation) {
link.style.animation = "";
} else {
link.style.animation = `navLinkFade 0.5s ease forwards ${index / 7 +
0.5}s`;
}
});
burger.classList.toggle("toggle");
};
return (
<div>
<nav>
<div className="logo">
<h3>College Facemash</h3>
</div>
<ul className="nav-links">
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/login">Login / Signup</Link>
</li>
</ul>
<div className="burger" onClick={navslide}>
<div className="line1"></div>
<div className="line2"></div>
<div className="line3"></div>
</div>
</nav>
</div>
);
}
}
export default navbar;
also i recommend adding state to your component and changing it when ham is clicked!
and then you can change elements classes depending on this state.

React state change

I am having difficulty in changing state. I would like to change the state with images in an array that has a corresponding description to the images in the array. On click on the chapter should bring up the image and the description. Could you tell me what I am doing wrong here? Ignore chapters 3-6 as I haven't populated that code.
import React from "react";
import {Component} from "react";
import Layout from "../components/layout";
import styles from "./book1.module.css";
import image1 from "../images/rainbow.jpg"
import image2 from "../images/rainbow2.jpg"
class book extends Component {
constructor() {
super();
this.state= {
index : 0,
images : [image1, image2],
ChapterDescriptions: ["chapter1","chapter2"]
}
}
chapter1=()=>{
this.setState({
index: this.state.images.index[0]
})
}
chapter2=()=>{
this.setState({
index: this.state.chapterImages[1]
})
}
chapter3=()=>{
this.setState({
index: this.state.chapter3.image
})
}
chapter4=()=>{
this.setState({
index: this.state.chapter4.image
})
}
chapter5=()=>{
this.setState({
index: this.state.chapter5.image
})
}
chapter6=()=>{
this.setState({
index: this.state.chapter6.image
})
}
render(){
return (
<Layout>
<div className={styles.container}>
<div className={styles.chapters}>
<h1>Anti-Children</h1>
<p>
Learn how our leaders subvert our children’s future and what you can
do to brighten it
</p>
<ul>
<br/>
<br/>
<li className={styles.description} onClick={this.chapter1} > aaaaaaa</li>
<li className={styles.description} onClick={this.chapter2}> bbbbbbbbb</li>
<li className={styles.description} onClick={this.chapter3}> ccccccccc</li>
<li className={styles.description} onClick={this.chapter4}> ddddddddd</li>
<li className={styles.description} onClick={this.chapter5}> eeeeeeeee</li>
<li className={styles.description} onClick={this.chapter6}> fffffffff</li>
</ul>
</div>
<div className={styles.bookimage}>
<img href="#" className={styles.chapterImage} src={this.state.images.index}/>
<div className={styles.textArea} > {this.state.ChapterDescriptions.index}</div>
</div>
</div>
</Layout>
)
}
}
export default book
I've edited and added some parts of the code.
1. You can render some looped tag using map()
{this.state.ChapterDescriptions.map((item,index)=>{
return <li className={style.description} onClick={()=>{handleIndex(index)}>{item}</li>
})
}
2. You can combine your click event for update the state
handleIndex = (index) => {
this.setState({ index: index });
}
3. etc.
<div className={styles.bookimage}>
<img href="#" className={styles.chapterImage} src={this.state.images[this.state.index]}/>
<div className={styles.textArea} > {this.state.ChapterDescriptions[this.state.index]}</div>
</div>
Full code
import React from "react";
import {Component} from "react";
import Layout from "../components/layout";
import styles from "./book1.module.css";
import image1 from "../images/rainbow.jpg"
import image2 from "../images/rainbow2.jpg"
class book extends Component {
constructor() {
super();
this.state= {
index : 0,
images : [image1, image2],
ChapterDescriptions: ["chapter1","chapter2"]
}
}
handleIndex = (index) => {
this.setState({ index: index });
}
render(){
return (
<Layout>
<div className={styles.container}>
<div className={styles.chapters}>
<h1>Anti-Children</h1>
<p>
Learn how our leaders subvert our children’s future and what you can
do to brighten it
</p>
<ul>
<br/>
<br/>
{
this.state.ChapterDescriptions.map((item,index)=>{
return <li className={style.description} onClick={()=>{handleIndex(index)}>{item}</li>
})
}
</ul>
</div>
<div className={styles.bookimage}>
<img href="#" className={styles.chapterImage} src={this.state.images[this.state.index]}/>
<div className={styles.textArea} > {this.state.ChapterDescriptions[this.state.index]}</div>
</div>
</div>
</Layout>
)
}
}
export default book
Please check this code with live example demo. if you want like this you can iterate through map instead of writing hard coded.
let data = [{id:1,chapter: "chapter 1", image:'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRZlA55Pm9_SZbN90fmVOYgldndkgqSv6k88kQMzvDh36i_no7J&s'},
{id:2,chapter: "chapter 2", image:'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQLZZPW62TuM_Qgtu8lMZJ1U9to8BM2A4dEmC27ZyDpzWq9ZAxe&s'},
{id:3,chapter: "chapter 3", image:'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRFnKI9xni86qgmhlkHTN6utr__NX_vtgzpQSVBsnKM0Zzb92pG4g&s'},
{id:4,chapter: "chapter 4", image:'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d9/Node.js_logo.svg/1200px-Node.js_logo.svg.png'},
{id:5,chapter: "chapter 5", image:'https://cdn2.iconfinder.com/data/icons/nodejs-1/512/nodejs-512.png'}]
class Book extends Component{
state={selected:''}
clickHandler=list=>{
this.setState({selected:list})
}
render(){
const {selected} =this.state;
return (
<div>
{data.map((d)=>
<p key={d.id} onClick={()=>this.clickHandler(d)}>
{d.chapter}
</p>
)}
<hr />
<h2>Please select an item from above list</h2>
{selected!==''&&<div>
<h3>{selected.chapter}</h3>
<img src={selected.image} alt="chapterimg"
style={{height:100,width:150}}/>
</div>}
</div>
)
}
}
check this for your reference Live demo
First, writing redundant <li> is not a good idea, you can change this by looping through a map function.
{
this.state.ChapterDescriptions.map((item,index)=>(
<li className={style.description} onClick={()=>this.setState({in
dex})}>
{item}
</li>)
}
and for showing the corresponding image
{
<div className={styles.bookimage}>
<img href="#" className={styles.chapterImage} src={this.state.images[this.state.index]}/>
<div className={styles.textArea} > {this.state.ChapterDescriptions[this.state.index]}</div>
</div>
}

My react SPA navigation currently renders the page for about a second and then goes back to my Main page

I am coding in react and my navigation will open the page I want and then immediately go back to the main page. I can't seem to wrap my head around what I might be doing wrong.
It is opening the new page so I feel like my ReactDOM Render below the main page is where everything is going wrong but I can't tell if it's just an issue with the way I've organized my code or the code itself.
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
class Main extends React.Component {
render(){
return (
<div>
<h1> React Playground </h1>
<ul className="header">
<li><a href="" onClick= {function () {
ReactDOM.render(<Playground />, document.getElementById('root'));
}}>Playground</a></li>
<li><a href="" onClick={function () {
ReactDOM.render(<Technology />, document.getElementById('root'));
}}>Technology</a></li>
<li><a href="" onClick={function () {
ReactDOM.render(<Library />, document.getElementById('root'));
}}>Library</a></li>
</ul>
</div>
);
}
}
ReactDOM.render(
<Main />,
document.getElementById("root")
);
//here is the Playground component for the Playground Page
class Playground extends React.Component {
render() {
document.title = "My Playground";
return (
<div>
<header>
<h1> My Playground </h1>
</header>
<nav>
<ul className="header">
<li><a href="" onClick= {function () {
ReactDOM.render(<Playground />, document.getElementById('root'));
}}>Playground</a></li>
<li><a href="" onClick={function () {
ReactDOM.render(<Technology />, document.getElementById('root'));
}}>Technology</a></li>
<li><a href="" onClick={function () {
ReactDOM.render(<Library />, document.getElementById('root'));
}}>Library</a></li>
</ul>
</nav>
</div>
);
}
}
//here is the Technology component for the Technology Page
class Technology extends React.Component {
render() {
document.title = "Fun Technology ";
return (
<div>
<h1> Fun Technology </h1>
<ul className="header">
<li><a href="" onClick= {function () {
ReactDOM.render(<Playground />, document.getElementById('root'));
}}>Playground</a></li>
<li><a href="" onClick={function () {
ReactDOM.render(<Technology />, document.getElementById('root'));
}}>Technology</a></li>
<li><a href="" onClick={function () {
ReactDOM.render(<Library />, document.getElementById('root'));
}}>Library</a></li>
</ul>
</div>
);
}
}
//here is the Library component for the Library page
class Library extends React.Component {
render() {
document.title = "Personal Library";
return (
<div>
<h1> Personal Library </h1>
<ul className="header">
<li><a href="" onClick= {function () {
ReactDOM.render(<Playground />, document.getElementById('root'));
}}>Playground</a></li>
<li><a href="" onClick={function () {
ReactDOM.render(<Technology />, document.getElementById('root'));
}}>Technology</a></li>
<li><a href="" onClick={function () {
ReactDOM.render(<Library />, document.getElementById('root'));
}}>Library</a></li>
</ul>
</div>
);
}
}
Here is the complete working example.
Your first issue I think is using multiple ReactDOM.renders. That's not the intended use case I'm afraid. You're supposed to use that once.
The second problem I see is duplicating your navigation three times. If you extract that into its own component and call it Navigation, you can render it only once. Like:
function Navigation(props) {
return (
<ul className="header">
<li>
<a href="#" onClick={() => props.onClick("playground")}>
Playground
</a>
</li>
<li>
<a href="#" onClick={() => props.onClick("technology")}>
Technology
</a>
</li>
<li>
<a href="#" onClick={() => props.onClick("library")}>
Library
</a>
</li>
</ul>
)}
Then you can use it this way:
function Main() {
const [page, setPage] = useState("playground");
return (
<div>
<Navigation onClick={setPage} />
{page === "playground" && <Playground />}
{page === "technology" && <Technology />}
{page === "library" && <Library />}
</div>
);
}
If you don't wanna use react-router for the route-based component rendering, then you need to introduce state and toggle the component based on the state. In the above Main component I have one state which can hold playground, technology or library and based on the current value we render the appropriate component.

Adding a CSS class to a JSX in ReactJS

I wanted to add an 'active' class to a menu element, written in ReactJS. I tried doing it with the conventional JS method, but it failed. A click on any <li> tag, should result is removal of the 'active' class from all the <li>, and retain/ add it only to the one list tag in which the click was triggered.
Note: I know it may seem very naive on my part, but I'm just starting with ReactJS. Please ignore the stupidity.
import React, { Component } from 'react';
class Sidebar extends Component{
render(){
return(
<div className="sidebarContainer p-2">
<div className="mainMenu">
<ul className="levelOne pl-0">
<li className="mb-3 pl-2 menuTitle active" id="MenuTitle1">
...
</li>
<li className="mb-3 pl-2 menuTitle" id="MenuTitle2" onClick={this.clickMenu.bind(this,'MenuTitle2')}>
...
</li>
<li className="mb-3 pl-2 menuTitle" id="MenuTitle3" onClick={this.clickMenu.bind(this,'MenuTitle3')}>
...
</li>
</ul>
</div>
</div>
);
}
clickMenu(id){
// Add class 'active' on the clicked <li>, and remove from all other <li>
}
}
export default Sidebar;
I saw a similar question here, but that couldn't help me.
Idea is, store the id of clicked item in state variable and put the check with className. If item's id is same as state value then only assign the className active.
Write it like this:
class Sidebar extends Component{
constructor() {
super()
this.state = {
activeItem: 'MenuTitle1'
}
}
clickMenu(id){
// Add class 'active' on the clicked <li>, and remove from all other <li>
this.setState({
activeItem: id,
})
}
getClassName(id) {
if(id === this.state.activeItem) return 'mb-3 pl-2 menuTitle active'
return 'mb-3 pl-2 menuTitle'
}
render(){
return(
<div className="sidebarContainer p-2">
<div className="mainMenu">
<ul className="levelOne pl-0">
<li
id="MenuTitle1"
className={this.getClassName('MenuTitle1')}
onClick={this.clickMenu.bind(this,'MenuTitle1')}>
...
</li>
<li
id="MenuTitle2"
className={this.getClassName('MenuTitle2')}
onClick={this.clickMenu.bind(this,'MenuTitle2')}>
...
</li>
<li
id="MenuTitle3"
className={this.getClassName('MenuTitle3')}
onClick={this.clickMenu.bind(this,'MenuTitle3')}>
...
</li>
</ul>
</div>
</div>
);
}
}
You can maintain the state for clicked menu item:
clickMenu(id){
this.setState({activeMenu: id})
}
Then, define className like this:
className={
this.state.activeMenu == id {/* eg. "MenuTitle1" */}
? 'mb-3 pl-2 menuTitle active'
: 'mb-3 pl-2 menuTitle'
}
Like Bhojendra suggested store datas linked to your display inside your state then when you want to update the display of your component use the method setState, this will trigger render again (react style).
import React, { Component } from 'react';
import ReactDOM from "react-dom";
class Sidebar extends Component {
constructor() {
super();
this.state = {
activeMenuId: "MenuTitle1"
};
}
render() {
return (
<div className="sidebarContainer p-2">
<div className="mainMenu">
<ul className="levelOne pl-0">
<li className={`mb-3 pl-2 menuTitle ${this.state.activeMenuId === "MenuTitle1" ? "active" : ""}`} id="MenuTitle1" onClick={this.clickMenu.bind(this, 'MenuTitle1')}>
1
</li>
<li className={`mb-3 pl-2 menuTitle ${this.state.activeMenuId === "MenuTitle2" ? "active" : ""}`} id="MenuTitle2" onClick={this.clickMenu.bind(this, 'MenuTitle2')}>
2
</li>
<li className={`mb-3 pl-2 menuTitle ${this.state.activeMenuId === "MenuTitle3" ? "active" : ""}`} id="MenuTitle3" onClick={this.clickMenu.bind(this, 'MenuTitle3')}>
3
</li>
</ul>
</div>
</div>
);
}
clickMenu(id) {
// Add class 'active' on the clicked <li>, and remove from all other <li>
this.setState({activeMenuId: id});
}
}
export default Sidebar;
ReactDOM.render(<Sidebar />, document.body);
Another way of just make using initialstate and setState.
import React, { Component } from "react";
class Sidebar extends Component {
constructor(props) {
super(props);
this.initialState = {
MenuTitle1: "active",
MenuTitle2: "",
MenuTitle3: ""
};
this.state = this.initialState;
}
render() {
return (
<div className="sidebarContainer p-2">
<div className="mainMenu">
<ul className="levelOne pl-0">
<li
className={`mb-3 pl-2 menuTitle ${this.state.MenuTitle1} `}
id="MenuTitle1"
onClick={this.clickMenu.bind(this, "MenuTitle1")}
>
one
</li>
<li
className={`mb-3 pl-2 menuTitle ${this.state.MenuTitle2}`}
id="MenuTitle2"
onClick={this.clickMenu.bind(this, "MenuTitle2")}
>
two
</li>
<li
className={`mb-3 pl-2 menuTitle ${this.state.MenuTitle3}`}
id="MenuTitle3"
onClick={this.clickMenu.bind(this, "MenuTitle3")}
>
three
</li>
</ul>
</div>
</div>
);
}
clickMenu(id) {
this.setState(this.initialState);
this.setState({
[id]: "active"
});
}
}
export default Sidebar;

Is there a way to click Navlink from within a function?

Basically, I'm delaying the navigation.
After clicking the Link, the onClick handler prevents the navigation by checking a condition and calls another function. If certain condition is met, then only the page navigates to another.
So how can I trigger Navlink click from within that function.
I was able to solve this problem by using event.preventDefault().
import React, { Component } from 'react'
import { NavLink } from 'react-router-dom'
import Modal from './Modal'
var confirmation = {};
class Example extends Component {
handleClick(event) {
if(this.props.data.length!=0) {
confirmation = {
prompt: (
<div className="row">
<div className="col s12 m5"><a className="btn" onClick={this.props.actions.toggleModal()}>No</a></div>
<div className="col s12 m7"><NavLink to={"/"+this.props.endpoint+"/1"} activeClassName="active" className="btn"}>Yes, Navigate to Option 1</NavLink></div>
</div>
)
}
event.preventDefault();
}
}
render() {
return (
<div>
<nav>
<div className="row">
<div className="col s10">
<ul className="col s12">
<li className="col s4 m4 l3"><NavLink to={"/"+this.props.endpoint+"/1"} activeClassName="active" onClick={this.handleClick.bind(this)}>Option 1</NavLink></li>
<li className="col s4 m4 l3"><NavLink to={"/"+this.props.endpoint+"/2"} activeClassName="active">Option 2</NavLink></li>
<li className="col s4 m4 l3"><NavLink to={"/"+this.props.endpoint+"/3"} activeClassName="active">Option 3</NavLink></li>
</ul>
</div>
</div>
</nav>
{
this.props.openModal ?
<Modal data={confirmation}/>
: null
}
</div>
)
}
}
export default example
Instead of using the react-router Link component, you can use their API to programmatically navigate to another page (if the certain condition is met).
export default class MyComponent extends Component {
navCheck(nextPage) {
if (someCondition) {
this.context.router.history.push(nextPage);
}
}
render() {
return(<a onClick={() => this.navCheck('/next-page')}>Navigate To Another Page</a>);
}
}
MyComponent.contextTypes = {
router: PropTypes.shape({
history: PropTypes.object.isRequired,
}),
};
More information on the official documentation: https://reacttraining.com/react-router/web/api/history

Resources