Changing state of component with OnClick in React - javascript

I am trying to change state of the component and render it to page.
var navbarValue = [{"Category":"Home","Status":1},{"Category":"About","Status":0},{"Category":"Contact","Status":0}];
class NavbarList extends React.Component {
constructor() {
super();
this.onClick = this.handleClick.bind(this);
}
handleClick(event) {
const {id} = event.target;
console.log(id);
if(!navbarValue[id].Status){
{navbarValue.map((obj, index) =>{
if(navbarValue[index].Status){
navbarValue[index].Status = 0;
return <li key={index}><a id={index} onClick={this.onClick}>{obj.Category} </a></li>
}
})}
navbarValue[id].Status = 1;
return <li className="active" key={id}><a id={id} onClick={this.onClick}>{navbarValue[id].Category}</a></li>
}
}
render() {
return (
<div className="navbar-wrapper">
<div className="container">
<nav className="navbar navbar-fixed-static-top navbar-inverse">
<div className="container">
<div className="navbar-header">
<button type="button" className="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span className="sr-only">Toggle navigation</span>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
</button>
<a className="navbar-brand" href="#">BrandName</a>
</div>
<div id="navbar" className="collapse navbar-collapse">
<ul className="nav navbar-nav">
{navbarValue.map((obj, index) => {
if (obj.Status)
return <li className="active" key={index}><a id={index} onClick={this.onClick}>{obj.Category}</a></li>
return <li key={index}><a id={index} onClick={this.onClick}>{obj.Category} </a></li>
})}
</ul>
</div>
</div>
</nav>
</div>
</div>
)};
};
ReactDOM.render(
<NavbarList />,
document.getElementById('root')
);
<script src="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
I have an if statement in handleClick(event) which validates if function has to be run and rerender elements.
First it checks if button which is already active is not being clicked. Next if statment is in loop to find previous active element, change objects property to 0 and render to not active.
At the end render new active element to active and set objects property to 1.

Put navbarValue in a state object and update the state onClick. You don't need if/else statements here. Because your components will be rerendered on state update.
Like this: https://stackoverflow.com/a/45134876/4953199

Related

Invalid hook cal

I am using Gatsby with the CSS framework Bulma, In order for the Mobile navbar to work, you have to add an event listener for a button that only becomes available when to screens size is a certain dimension. in previous versions of Gatsby, it worked fine, only in the recent week have I been running to problems. Now I get an Invalid hook call
import { Link } from 'gatsby'
let Header = () => {
useEffect(() => {
let burger = document.getElementById(`burger`);
let menu = document.getElementById(`navMenu`)
burger.addEventListener(`click`, function () {
burger.classList.toggle(`is-active`);
menu.classList.toggle(`is-active`)
})
});
return (
<>
<nav className="navbar is-fixed-top" id="navbar">
<div className="navbar-brand">
<Link to="/">
<p className="navbar-item">CMJR DEVELOPMENT</p>
</Link>
<a role="button" id="burger" className="navbar-burger burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div className="navbar-menu" id="navMenu">
<div className="navbar-end">
<Link to={"/service"} className="navbar-item ">Services</Link>
<Link to={"/portfolio"} className="navbar-item ">Portfolio</Link>
<Link to={"/contact"} className="navbar-item ">Contact</Link>
</div>
</div>
</nav>
</>
)
}
export default Header;
I know I'm doing something wrong, just not what.

How to access ReactJS DOM elements using JQuery

I am trying to get the height of the header element using Jquery's height() method. But it gives NAN when I console the values
Here's my react snippet
import React, { Component } from "react";
import $ from 'jquery'; //un-used
export default class HomepageNavigationBar extends Component {
render() {
return (
<header className="header_area">
<div className="main_menu">
<nav className="navbar navbar-expand-lg navbar-light">
<div className="container">
<a className="navbar-brand logo_h" href="index.html">
<img src="img/logo.png" alt="" />
</a>
<button
className="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span className="icon-bar" /> <span className="icon-bar" />
<span className="icon-bar" />
</button>
.
.
.
//dots used to denote that code further exists but to make this minimal I have removed them.
</div>
</header>
);
}
}
and here's my external theme.js file
(function($) {
"use strict";
var nav_offset_top = $("header").height() + 50;
console.log(nav_offset_top); //gives 'NAN' when console, even after I scroll
function navbarFixed() {
if ($(".header_area").length) {
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= nav_offset_top) {
alert('Hi');
$(".header_area").addClass("navbar_fixed");
} else {
alert('no Hi');
$(".header_area").removeClass("navbar_fixed");
}
});
}
}
navbarFixed();
})(jQuery);
Problems are:
1)
console.log(nav_offset_top);
this above code gives NAN when console the value even after I scroll the page up and down
2)
$(".header_area").length
header_area length is always 0 even after I scroll up and down the page
Can someone here help me out?
I believe you're getting NaN because you're accessing header when it is not yet rendered.
Put your code in componentDidMount() instead to make sure that elements are rendered before accessing it.
Read more: https://reactjs.org/docs/react-component.html#componentdidmount
The docs state that:
Initialization that requires DOM nodes should go here.
This is exactly what you're doing, accessing DOM nodes using jQuery.
class HomepageNavigationBar extends React.Component {
componentDidMount() {
var nav_offset_top = $("header").height() + 50;
console.log(nav_offset_top);
function navbarFixed() {
if ($(".header_area").length) {
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= nav_offset_top) {
alert('Hi');
$(".header_area").addClass("navbar_fixed");
} else {
alert('no Hi');
$(".header_area").removeClass("navbar_fixed");
}
});
}
}
navbarFixed();
}
render() {
return (
<header className="header_area">
<div className="main_menu">
<nav className="navbar navbar-expand-lg navbar-light">
<div className="container">
<a className="navbar-brand logo_h" href="index.html">
<img src="img/logo.png" alt="" />
</a>
<button
className="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span className="icon-bar" /> <span className="icon-bar" />
<span className="icon-bar" />
</button>
</div>
</nav>
</div>
</header>
);
}
}
ReactDOM.render(<HomepageNavigationBar />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root" style="height: 1000px;"></div>

How to place glyphicon in bootstrap navbar within a react.js project

How can I display a glyphicon in a bootstrap navbar? I have a React.js project that I have been working on, and I would like to relocate the GitHub glyphicon to the navbar. So far I have something looking like the below.
The code pertaining to the navbar in the App.js
import React, {PropTypes} from 'react';
import NavBar from './common/NavBar-test';
import FontAwesome from 'react-fontawesome';
var navbar = {};
navbar.brand = {linkTo: "#", text: "app"};
navbar.links = [
{linkTo: "#Demonstration", text: "Demonstration"},
{linkTo: "#Demonstration2", text: "Demonstration #2"},
{linkTo: "https://github.com/user/app", text:"GitHub Source Code"},
{linkTo: "https://itunes.apple.com/us/app/", text: "App Store"},
{linkTo: "https://github.com/user/appr", text: "The Future of app"}
];
And Navbar-test.js
import React, { PropTypes } from 'react';
// create classes
var NavBar = React.createClass({
render: function(){
return(
<nav className="navbar navbar-default navbar-static-top">
<div className="container-fluid">
<div className="navbar-header">
<button type="button" className="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse" aria-expanded="false">
<span className="sr-only">Toggle navigation</span>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
</button>
<NavBrand linkTo={this.props.brand.linkTo} text={this.props.brand.text} />
</div>
<div className="collapse navbar-collapse" id="navbar-collapse">
<NavMenu links={this.props.links} />
</div>
</div>
</nav>
);
}
});
var NavBrand = React.createClass({
render: function(){
return (
<a className="navbar-brand" href={this.props.linkTo}>{this.props.text}</a>
);
}
});
var NavMenu = React.createClass({
render: function(){
var links = this.props.links.map(function(link){
if(link.dropdown) {
return (
<NavLinkDropdown key={link.text} links={link.links} text={link.text} active={link.active} icon={link.icon} />
);
}
else {
return (
<NavLink key={link.text} linkTo={link.linkTo} text={link.text} active={link.active} />
);
}
});
return (
<ul className="nav navbar-nav">
{links}
</ul>
);
}
});
var NavLinkDropdown = React.createClass({
render: function(){
var active = false;
var links = this.props.links.map(function(link){
if(link.active){
active = true;
}
return (
<NavLink key={link.text} linkTo={link.linkTo} text={link.text} active={link.active} />
);
});
return (
<li className={"dropdown " + (active ? "active" : "")}>
<a href="#" className="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
{this.props.text}
<span className="caret"></span>
</a>
<ul className="dropdown-menu">
{links}
</ul>
</li>
);
}
});
var NavLink = React.createClass({
render: function(){
return(
<li className={(this.props.active ? "active" : "")}>
<a href={this.props.linkTo}>{this.props.text}{this.props.icon}</a>
</li>
);
}
});
export default NavBar;
Ideally, I'd like to place the GitHub glyphicon in front of the text that states GitHub Source Code.
It looks like you are mapping over the links (which is cool), but you can add your desired GitHub data before the mapped links.
You might end up with something like this:
<span>
<NavLink>GitHub Source Code</NavLink>
<GlyphIcon />
</span>
// Then map over links here
In short, I finally got the glyphicons to display how I would like them to.
I needed to modify the source of the Navbar-test to support icons.
Something like,
class NavMenu extends React.Component {
render() {
var links = this.props.links.map(function(link){
if(link.dropdown) {
return (
<NavLinkDropdown key={link.text} links={link.links} text={link.text} active={link.active} icon={link.icon} />
);
}
else {
return (
<NavLink key={link.text} linkTo={link.linkTo} icon={link.icon} text={link.text} active={link.active} />
);
}
});
return (
<ul className="nav navbar-nav">
{links}
</ul>
); // close return
} // close render
} // close NavMenu

Rerender functional component when prop changes

I'm having trouble rerendering component when parent state passed to child component changes. MapNav component contains buttons which triggers methods changing current displayed popup. My problem is to re-render UserPopup button when someone clicks zaloguj or wyloguj, it should work but it does not and i cant figure out what is wrong also i don't want to trigger animation when isLoggedIn state changes and one more thing logIn method changes state properly. isLoggedIn state is just temporary later i'll change that to use store instead. I'm trying to write as much functional component but in some cases i cant avoid using state and i bet that there are issues in my code so i'll appreciate all improvement tips.
const MapNav = (props) => {
return <div className={'mapNavContainer'}>
<ul className={'navList'}>
<li><i className={"glyphicon glyphicon-fullscreen"} /></li>
<li><i className={"glyphicon glyphicon-chevron-left"} /></li>
<li><i className={"glyphicon glyphicon-chevron-right"} /></li>
<li><i className={"glyphicon glyphicon-map-marker"} /></li>
<li><a href="#" onClick={props.onUserIconClick}><i className={"glyphicon glyphicon-user"} /></a></li>
<li><a href="#" onClick={props.onInfoClick}><i className={"glyphicon glyphicon-info-sign"} /></a></li>
</ul>
</div>
}
const UserPopup = (props) => {
return <div>
{(props.isLoggedIn) ? (
<div className={'navPopups col-sm-3 panel panel-default'}>
<div className={"panel-heading"}>Zalogowany</div>
<div className={"panel-body"}>
<button type='submit' onClick={props.logIn}>wyloguj</button>
</div>
</div>
) : (
<div className={'navPopups col-sm-3 panel panel-default'}>
<div className={"panel-heading"}>Niezalogowany</div>
<div className={"panel-body"}>
<button type='submit' onClick={props.logIn}>Zaloguj</button>
</div>
</div>
)
}
</div>;
};
function Welcome(props) {
return <div className={'navPopups col-sm-3 panel panel-default'}>
<div className={"panel-heading"}>Informacje o Autorze.</div>
<div className={"panel-body"}>
Basic panel example
</div>
</div>;
}
class MapHeader extends React.Component {
constructor(props) {
super(props);
this.state = {
currentPopup: null,
isLoggedIn: false,
username: 'gregorowicz.k#gmail.com',
};
this.onInfoClick = this.onInfoClick.bind(this);
this.onUserIconClick = this.onUserIconClick.bind(this);
this.logIn = this.logIn.bind(this);
}
onInfoClick = (e) => {
e.preventDefault();
this.setPopup(<Welcome />);
}
onUserIconClick = (e) => {
e.preventDefault();
const loginPopup = <UserPopup isLoggedIn={this.state.isLoggedIn} username={this.state.username} logIn={this.logIn} />;
this.setPopup(loginPopup);
}
setPopup = (obj) => {
this.state.currentPopup === null ? this.setState({ currentPopup: obj }) : this.setState({ currentPopup: null });
}
logIn = (e) => {
this.setState({ isLoggedIn: !this.state.isLoggedIn });
}
render() {
return (
<nav className={'header'}>
<div className={'container-fluid'}>
<div className={"navbar-header"}>
<button type="button" className={"navbar-toggle collapsed"} data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span className={"sr-only"}>Toggle navigation</span>
<span className={"icon-bar"} />
<span className={"icon-bar"} />
<span className={"icon-bar"} />
</button>
</div>
<div id={"navbar"} className={'navContainer'}>
{MapNav({onInfoClick:this.onInfoClick, onUserIconClick:this.onUserIconClick})}
{this.state.currentPopup ? this.state.currentPopup : null}
</div>
</div>
</nav>
)
}
}
// Render it
ReactDOM.render(
<MapHeader />,
document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css" />
I've solved it. There is currentPopup state in my code which stored current popup displayed, to see changes i had to unmount and mount component again after isLogggedIn state changed, so i've changed the way to display current popup. Instead storing whole component in state, i store just simple string values which provide information about current component. Anyway thank you for tips, i'll surely apply them in my code.
const MapNav = (props) => {
return <div className={'mapNavContainer'}>
<ul className={'navList'}>
<li><i className={"glyphicon glyphicon-fullscreen"} /></li>
<li><i className={"glyphicon glyphicon-chevron-left"} /></li>
<li><i className={"glyphicon glyphicon-chevron-right"} /></li>
<li><i className={"glyphicon glyphicon-map-marker"} /></li>
<li><a href="#" onClick={props.onUserIconClick}><i className={"glyphicon glyphicon-user"} /></a></li>
<li><a href="#" onClick={props.onInfoClick}><i className={"glyphicon glyphicon-info-sign"} /></a></li>
</ul>
</div>
}
const UserPopup = (props) => {
return <div>
{(props.isLoggedIn) ? (
<div className={'navPopups col-sm-3 panel panel-default'}>
<div className={"panel-heading"}>Zalogowany</div>
<div className={"panel-body"}>
<button type='submit' onClick={props.logIn}>wyloguj</button>
</div>
</div>
) : (
<div className={'navPopups col-sm-3 panel panel-default'}>
<div className={"panel-heading"}>Niezalogowany</div>
<div className={"panel-body"}>
<button type='submit' onClick={props.logIn}>Zaloguj</button>
</div>
</div>
)
}
</div>;
};
function Welcome(props) {
return <div className={'navPopups col-sm-3 panel panel-default'}>
<div className={"panel-heading"}>Informacje o Autorze.</div>
<div className={"panel-body"}>
Basic panel example
</div>
</div>;
}
class MapHeader extends React.Component {
constructor(props) {
super(props);
this.state = {
currentPopup: null,
isLoggedIn: null,
};
this.onInfoClick = this.onInfoClick.bind(this);
this.onUserIconClick = this.onUserIconClick.bind(this);
this.logIn = this.logIn.bind(this);
}
onInfoClick = (e) => {
e.preventDefault();
this.setState({ currentPopup: this.state.currentPopup === 'info' ? null : 'info' });
}
onUserIconClick = (e) => {
e.preventDefault();
this.setState({ currentPopup: this.state.currentPopup === 'user_login' ? null : 'user_login' });
}
setPopup = (obj) => {
this.setState({ currentPopup: this.state.currentPopup === 'user_login' ? null : 'user_login' });
}
logIn = (e) => {
this.setState({ isLoggedIn: !this.state.isLoggedIn });
}
render() {
return (
<nav className={'header'}>
<div className={'container-fluid'}>
<div className={"navbar-header"}>
<button type="button" className={"navbar-toggle collapsed"} data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span className={"sr-only"}>Toggle navigation</span>
<span className={"icon-bar"} />
<span className={"icon-bar"} />
<span className={"icon-bar"} />
</button>
</div>
<div id={"navbar"} className={'navContainer'}>
{MapNav({onInfoClick:this.onInfoClick, onUserIconClick:this.onUserIconClick})}
{this.state.currentPopup === 'info' ? <Welcome /> : null}
{this.state.currentPopup === 'user_login' ? (
<UserPopup isLoggedIn={this.state.isLoggedIn} logIn={this.logIn} />
) : null}
</div>
</div>
</nav>
)
}
}
// Render it
ReactDOM.render(
<MapHeader />,
document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css" />

React.js modify child element on parent click

I have a following react component:
<li key={contact.id} class="option contact-item">
<div class="thumbnail">
<a><span>{contact.name.slice(0, 1)}</span></a>
</div>
<div class="text">
<div class="label">
<div class="name">{contact.name}</div>
<div class="status">{contact.status}</div>
</div>
<div class="select-container">
<div class="select">
<i class="icon-check"></i>
</div>
</div>
</div>
</li>
I need to toggle the color of <i class="icon-check"></i> when clicking the whole <li>
How can I do that?
Firstly, in react, you don't use class, you use className.
See this for full code: https://codepen.io/pen?editors=0010
Using state, you can change styles/classes/etc
_handleClick(key) {
let clicked = this.state.myList.filter(f => f.id === key)[0];
this.setState({ clicked: clicked });
}
_changeColor(key) {
if (this.state.clicked.id === key) {
return 'icon-checked';
}
else
return 'icon-check';
}
_renderList() {
return this.state.myList.map(contact => (
<li key={contact.id}
onClick={() => this._handleClick(contact.id)}
className="option contact-item">
<i className={this._changeColor(contact.id)}></i>
{contact.name}
</li>
));
}
render() {
return (
<div>
<h1>Hello</h1>
<ul>
{this._renderList()}
</ul>
</div>
);
}
You can set "changeColor" state on <li> click and your <i> can handle this state. If you change component state React will rerender your component.
<li onClick={this.changeColor()} key={contact.id} className="option contact-item">
<div className="thumbnail">
<a><span>{contact.name.slice(0, 1)}</span></a>
</div>
<div className="text">
<div className="label">
<div className="name">{contact.name}</div>
<div className="status">{contact.status}</div>
</div>
<div className="select-container">
<div className="select">
<i className="icon-check" style={if (this.state.colorChanged) {color: 'red'}}></i>
</div>
</div>
</div>
changeColor() {
this.setState({colorChanged: true});
}
I made a simple example for you, it works with a sinle list item Check this out.
If you have a list of items, you need to add a one more component for List itself with onToggleListItem method, which will handle the state change. The state of all list items should be store there. In ListItem component you call the onToggleListItem method with a contact id so you can identify which list item was changed.
handleButtonClick() {
this.props.onToggleListItem(this.props.contact.id);
}
Make use of a state and change the state on click of li
var Hello = React.createClass({
getInitialState() {
return {
colorClass: ''
}
},
toggleClass() {
if(this.state.colorClass == '') {
this.setState({colorClass: 'someColor'});
} else {
this.setState({colorClass: ''});
}
},
render(){
return (
<div>
<li onClick={this.toggleClass}>
Some text
<i className={"icon-check " + this.state.colorClass}>value</i>
</li>
</div>
);
}
})
ReactDOM.render(<Hello />, document.getElementById('app'));
.someColor {
color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="app"></div>

Categories