Change class component state from another component - javascript

i take my first steps on react.
I'm working on a gatsbyjs site, and i'm stuck on my nav component.
Following some tuts, I started creating a class component called Burger to show/hide the nav... setting props, state and bind.. no probs right now.
On another file i put my Nav functional components, using gatsbyjs "Link" component to manage links.
What i'm trying to do, is to change the state of the "Burger" component when I click on the link.
So I tried using the onClick event:
onClick={() => props.handleClick()}
it doesn't work and the error is: props.handleClick is not a function.
What im doing wrong?
thanks
// Burger.js
class Burger extends React.Component {
constructor(props) {
super(props);
this.state = { isOpen: false };
this.handleClick = this.handleClick.bind(this);
}
handleClick = () => {
this.setState({
isOpen: !this.state.isOpen,
});
this.state.isOpen
? document.body.classList.remove("nav-open")
: document.body.classList.add("nav-open");
};
render() {
const burgerState = this.state.isOpen ? open : "";
return (
<button className={`${burger} ${burgerState}`} onClick={this.handleClick}>
<span className={burger__label}>Menu</span>
<span className={burger__line}></span>
<span className={burger__line}></span>
<span className={burger__line}></span>
</button>
);
}
}
// Nav.js
const Nav = (props) => {
return (
<div className={nav__overlay}>
<div className={nav__wrap}>
<nav className={nav__primary}>
<ul>
<li>
<Link to='/' activeClassName={active} title='Home' onClick={() => props.handleClick()}>
Home
</Link>
</li>
<li>
<Link to='/about' activeClassName={active} title='About' onClick={() => props.handleClick()}>
About
</Link>
</li>
<li>
<Link to='/contact' activeClassName={active} title='Contact' onClick={() => props.handleClick()}>
Contact
</Link>
</li>
<li>
<Link to='/blog' activeClassName={active} title='Blog' onClick={() => props.handleClick()}>
Blog
</Link>
</li>
</ul>
</nav>
<div className='contact'>
<ul>
<li>aaa</li>
<li>aaa</li>
<li>aaa</li>
<li>aaa</li>
</ul>
</div>
</div>
</div>
);
};

Is the error with the Burger component or the Nav component? It's not clear how Nav.js or Burger.js are related or interact with one another. Another thing is that React doesn't care if the nav-open class is on the body or not, so if hooked up properly the function should be callable.
Given the error you provided — onClick={() => props.handleClick()} — it looks like this code is in the Nav component. Wherever you render the nav, you need to pass handleClick as a prop, e.g. <Nav handleClick={myFunction} />.
You can read more about props and how they work here: https://reactjs.org/docs/components-and-props.html

Related

React JS - custom accordion content won't slide open

Here's what I've have so far - Full working view https://codesandbox.io/s/hungry-elbakyan-v3h96
Accordion component:
const Accordion = ({ data }) => {
return (
<div className={"wrapper"}>
<ul className={"accordionList"}>
{data.map((item) => {
return (
<li className={"accordionListItem"} key={item.title}>
<AccordionItem {...item} />
</li>
);
})}
</ul>
</div>
);
};
const AccordionItem = ({ content, title }) => {
const [state, setState] = useState({
isOpened: false
});
return (
<div
className={cn("accordionItem", state.isOpened && "opened")}
onClick={() => setState({ isOpened: !state.isOpened })}
>
<div className={"lineItem"}>
<h3 className={"title"}>{title}</h3>
<span className={"icon"} />
</div>
<div className={"inner"}>
<div className={"content"}>
<p className={"paragraph"}>{content}</p>
</div>
</div>
</div>
);
};
When I click on the accordion item nothing happens. I can see the content appears in inspect and the state changes as expected but it doesn't slide down. Did I miss something in my css or component?
Here is what I was able to achieve. You may not like it completely(animations). But things seems sorted
https://codesandbox.io/s/relaxed-babbage-2zt4f?file=/src/styles.css
props name was not right for accordion body
and styles need to be changes once the accordion is in open state.
You need to add or remove the className inner when state.isOpen so you can see your content

Converting CSS and HTML hamburger menu into a react component

I am following a tutorial that creates an animated navbar and hamburger manu using css, html and javascript, and I want to create the navbar as a react component for my project.
The code that I am trying to covert is the following, which is an app.js file which is embedded in the html with tags:
const navSlide = () => {
const burger = document.querySelector('.burger');
const nav = document.querySelector('.nav-links');
burger.addEventListener('click', () => {
nav.classList.toggle('nav-active');
})
}
navSlide();
I have tried to implement this code into my navbar react component as follows:
import React from "react";
const NavBar = () => {
const nav = document.querySelector(".nav-links");
return (
<div className="navbar">
<nav>
<ul className="nav-links">
<li>
Menu Item
</li>
</ul>
<div
className="burger"
onClick={() => {
nav.classList.toggle("nav-active");
}}
>
<div className="line1" />
<div className="line2" />
<div className="line3" />
</div>
</nav>
</div>
);
};
export default NavBar;
However this returns the error of:
"TypeError: Cannot read property 'classList' of null"
The CSS of .nav-active is as follows:
.nav-active {
transform: translateX(0%);
}
The result of this I am expecting is for the navbar to toggle open and closed when the burger symbol is clicked
The best option is to go with state. This is should work, have not tested though. ReactJS 16.8 is required for useState hook to work.
import React, {useState} from "react";
const NavBar = () => {
const [navOpened, setNavOpened] = useState(false);
const navClassNames = navOpened ? 'nav-links nav-active' : 'nav-links';
return (
<div className="navbar">
<nav>
<ul className={navClassNames}>
<li>
Menu Item
</li>
</ul>
<div
className="burger"
onClick={() => setNavOpened(!navOpened)}
>
<div className="line1" />
<div className="line2" />
<div className="line3" />
</div>
</nav>
</div>
);
};
To refer to DOM elements you should be using ref, you can use a useRef hook docs.
import React, { useRef } from "react";
const NavBar = () => {
const nav = useRef(null); // initial value of ref null
return (
<div className="navbar">
<nav>
<ul className="nav-links" ref={nav}> {/* Put the ref in your JSX */}
<li>
Menu Item
</li>
</ul>
<div
className="burger"
onClick={() => {
nav.current.classList.toggle("nav-active"); // Now you can use the ref here, current is required to get the current value of the ref
}}
>
<div className="line1" />
<div className="line2" />
<div className="line3" />
</div>
</nav>
</div>
);
};
export default NavBar;

how to use react-springy-parallax

How do I use the scrollTo in react-springy-parallax?
I'm trying to use react-springy-parallax in a simple portfolio page, you can click to springy parallax scroll to the next page but I want to be able to use nav links as well, here is how the app is laid out:
App.js
class App extends React.Component {
constructor() {
super()
this.ref = 'parallax'
}
render() {
return (
<div>
<Parallax ref={this.ref} pages={4}>
<Parallax.Layer
offset={0}
speed={0.5}
onClick={() => this.refs.parallax.scrollTo(1)}
>
<Nav />
<Header />
</Parallax.Layer>
...
So the onClick here just scrolls to the next page, I want to be able to say in my Nav component click the About link and it will scroll +1 so scrollTo(1)
Here is the nav component:
Nav.js
class Nav extends React.Component {
render() {
return (
<div className="nav">
<ul className="links">
<li>
About
</li>
...
I did try importing the scrollTo named export from react-springy-parallax into the nav component but got an error in the Chrome dev console saying it's not a function
I'm now trying to use a click handler:
class Nav extends React.Component {
render() {
function handleClick(e) {
e.preventDefault()
console.log(e)
}
return (
<div className="nav">
<ul className="links">
<li>
<a
href="#"
onClick={handleClick}
>
About
</a>
</li>
...
But I don't know how to call back to App.js to call the scrollTo
Anyone have any ideas?
logged an issue with the repo owner and he was kind enough to give a few pointers:
Use contextTypes to access the scrollTo method from parallax
In the Nav component use:
Nav.contextTypes = { parallax: React.PropTypes.object }
This will allow you to use the scrollTo method
Something like:
class Nav extends React.Component {
render() {
return (
<div className="nav">
<ul className="links">
<li>
<a
href=""
onClick={this.context.parallax.scrollTo(0)}
>
Home
</a>
</li>
<li>
<a
href=""
onClick={this.context.parallax.scrollTo(1)}
>
About
</a>
</li>
You can also pass the function as a prop, like so:
class App extends React.Component {
constructor(props) {
super(props)
this.handleScroll = value => this.parallax && this.parallax.scrollTo(value)
}
render() {
return (
<div>
<Parallax
ref={ref => (this.parallax = ref)}
pages={4}
>
<Parallax.Layer
offset={0}
speed={0.5}
onClick={() => this.handleScroll(1)}
>
<Nav handleScroll={this.handleScroll} />
Then from the Nav component use props onClick={() => this.props.handleScroll(PAGE)} with PAGE being the page number you want to scroll to.

How to use onClick event with <Link> in reactjs

i am trying to get the Id of a student by clicking on the . But it's giving me error like TypeError: Cannot read property 'handleClick' of undefined. What's wrong in here.?? First atleast i need to get this handleClick function to be working.
This is my react code:
class Premontessori extends React.Component{
constructor(props){
super(props);
this.state={
post:[],
id:[]
};
this.handleClick = this.handleClick.bind(this);
}
handleClick(event) {
alert(event);
}
componentDidMount(){
let self = this;
axios.get('http://localhost:8080/list')
.then(function(data) {
//console.log(data);
self.setState({post:data.data});
self.setState({id:data.data})
});
}
render(){
console.log(this.state.id);
return(
<div className="w3-container">
<div className="w3-display-container">
<div className="w3-panel w3-border w3-yellow w3-padding-4 w3-xxlarge ">
<p >List Of Students</p>
<div className="w3-display-right w3-container">
<Link className="w3-btn-floating w3-yellow" style={{textDecoration:'none',float:'right'}} to="/createstudent">+</Link>
</div></div>
</div>
<ul className="w3-ul w3-card-4 w3-yellow"> {this.state.post.map(function(item, index) {
return (
<Link to="/displaylist" style={{textDecoration:'none'}} key={index} onClick={this.handleClick}>
<li className=" w3-hover-green w3-padding-16" >
<img src={require('./3.jpg')} className="w3-left w3-circle w3-margin-right " width="60px" height="auto" />
<span>{item.Firstname}</span><br/><br/>
</li>
</Link>
)}
)}
</ul>
</div>
);
}
}
export default Premontessori;
When you pass this.handleClick to Link, at the moment the event happens and function gets executed, the latter happens in context of instance of Link. And since Link component doesn't have handleClick prop, the operation fails.
Try to declare handleClick in a way it gets bound to current component at the time of instantiation:
handleClick = event => {
alert(event);
}
Or use Function#bind in your render function:
<Link onClick={this.handleClick.bind(this)} />
Link is already has an internal hanlder for clicking which is redirection to another Route , and it is a markup solution .
React router provides also a non-markup solution to redirect which is browserHistory.push.
Thus :
import {browserHistory} from 'react-router'
handleClick(event) {
event.preventDefault();
alert('you clicked me');
browserHistory.push('/displaylist');
}
<a style={{textDecoration:'none'}} key={index} onClick={this.handleClick}></a>
Instead of
import {Link} from 'react-router'
<Link to="/displaylist" style={{textDecoration:'none'}} key={index} onClick={this.handleClick}>

Get arguments from another component [React JS]

I'm creating a web-app using React. I'm facing a problem with my navbar and the main content:
In AppWrapper I have this:
var contents = [
<Offers />,
<Create />,
<List />
];
and where each item will be the content displaying.
In getInitialState I initialize it like this:
getInitialState: function() {
return {
currentTab: 0
};
},
Later, in render function I have this:
return (
<div>
<Navbar />
<div className='mainPanel'>
{contents[this.state.currentTab]}
</div>
</div>
);
You can see that I call the navbar component before the content.
In Navbar component I have a menu where, from there, I want to change the currentTab of AppWrapper.
How can I do that? Thank you for advance!
After trying to handle it, I found how to do that.
This is the answer:
<Navbar selectTab={this.selectTab} />
selectTab: function(tab) {
this.setState({ currentTab: tab });
}
I pass to Navbar component the function "selectTab of the parent (AppWrapper).
Then in Navbar component:
<li>
<a onClick={this.selectTab.bind(this, 0)}><i className="fa fa-dashboard fa-fw" /> Dashboard</a>
</li>
<li>
<a onClick={this.selectTab.bind(this, 1)}><i className="fa fa-edit fa-fw" /> Create</a>
</li>
Then in selectTab of Navbar I change the props to current tab.
selectTab: function(tab) {
this.props.selectTab(tab);
},
Hope someone helps this answer!

Categories