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!
Related
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
I know about the scrollBehavior function that Vue has, but I am unsure of how to use it with my code.
I have an Index page, where sections are made of imported vue components.
For example
<template>
<div class="Container">
<About />
<Services />
<Contact />
</div>
</template>
My Navbar has links to all these components.
<template>
<nav>
<img class="nav__logo" :src="navLogo" height="40px" width="auto">
<ul class="nav__row" ref="nav">
<div class="nav__row__dropdown-toggle-btn" #click="toggleNav">
<img :src="navMenuIcon" height="40px" width="auto">
</div>
<li class="nav__list-item" v-for="(link, index) in navLinks" :key="index"
#mouseover="hover = true"
#mouseleave="hover = false"
:class=" { active: hover } ">
<router-link :to="link.path">
{{ link.text }}
</router-link>
</li>
</ul>
</nav>
</template>
which it gets from my App.vue script
<script>
import Navbar from '#/components/Navbar'
import Footer from '#/components/Footer'
export default {
components: {
Navbar,
Footer
},
data: () => ({
navLinks: [
{
text: 'Home',
path: '/'
},
{
text: 'About',
path: '/about'
},
{
text: 'Contact',
path: '/contact'
},
{
text: 'Services',
path: '/services'
}
]
})
}
</script>
but if I click on "About" it will just take me to a seperate page for the "About" component.
When I click on "About" I want the page to scroll down to the imported About component that is nested on my Index page.
How can I accomplish this? Is it something I need to change in the path?
The idea of router that you trying to implement is actually treating About components as a page, and when clicking at it, it will go to that page (and change URL)
So, in order to implement what you want, I actually suggest using pure javascript
First, give the About component and id ( or ref if you prefer Vue ref)
<template>
<div class="Container">
<About id="about"/>
<Services />
<Contact />
</div>
</template>
Then bind a method to click event of nav
<li class="nav__list-item" v-for="(link, index) in navLinks" :key="index"
#mouseover="hover = true"
#mouseleave="hover = false"
:class=" { active: hover } ">
#click=nav(link)
</li>
data: () => ({
navLinks: [
{
text: 'About',
id: 'about'
}
]
}),
methods:{
nav(link) {
const position = document.getElementById(link.id).offsetTop;
// smooth scroll
window.scrollTo({ top: position, behavior: "smooth" });
}
}
If you prefer Vue ref, can change all id to ref. And use this.$refs[link.id].$el.offsetTop instead;
i found this video so useful,
my goal was able to scroll between component at the same page.
but still you can apply anywhere, i think
https://laracasts.com/series/practical-vue-components/episodes/1
I keep getting this error when attempting to update a component with new data fetched from a server.
Description:
Portfolio.js
I have an app that has a portfolio where the projects of the site are shown. When you click an item in portfolio, you are redirected (with react-router) to the individual project.
Project.js
The project component uses the fetch api to retrieve data from a server. Which works perfectly because when the url specifies the project to be show like: /portfolio/project/:id, and based on the id received the data is fetched and displayed correctly.
The data retrieved
What is retrieved trough fetch api is just the result of a AJAX POST request to a server with the only parameter of the project id, which only returns the info of the project. (name, description, images, and other ones not much important)
The issue:
As far I've analyzed the application to see when this error is triggered, I found that this warning comes out when the amount of images for the new project loaded is smaller than the amount of images of the project already rendered.
An example:
We are inside a project. The url is portfolio/project/1 and the server data returned that this project has 5 images. They are loaded and you can view the project correctly.
Now, we use the menu to react-router-redirect to portfolio/project/2 and the server returned data with 7 images. They are loaded and the project data as well to view the project.
So, let say that we choose the option in the menu to view the project portfolio/project/3 which has 3 images, and then the warning comes up.
Browser:
Console log:
The code:
Since the error says the problem is inside Project.js, I am only adding this code so the question doesn't look overloaded and full of weird code.
Project.js
import React,{Component} from 'react'
import Footer from '../Footer/Footer'
import Header from '../Header'
import SubNav from '../SubNav'
import Details from './Details'
import {Link} from 'react-router-dom'
import {Configurations} from '../AppConfig'
class Project extends Component{
state = {
projectInfo: null,
reloadHandlerActive: false,
projectID : this.props.match.params.id,
projectName: "",
topProjectInfo: [],
images: []
}
createImages = (project) =>{
let Images = Object.values(project.images),
ImagesURI = Images.map((img, index)=>{
if( img.includes('Desarrollos.jpg') || img.includes('Home.jpg') || img.includes('H.jpg') ){
return null
}
return project.path+img
})
ImagesURI = ImagesURI.filter(function (e) { //Clear null values
return e != null;
})
return ImagesURI
}
reloadHandler = (id) =>{
const {createImages} = this
fetch(Configurations.API.projectInfo(id))
.then((result)=>{return result.json() })
.then((project)=>{
if(project === "error"){
alert("Error")
}else{
this.setState({
projectInfo: project,
images: createImages(project)
},function(){
document.getElementsByClassName("nav-button")[0].click()
})
}
})
}
componentWillMount(){
const {createImages} = this
fetch(Configurations.API.projectInfo(this.state.projectID))
.then((result)=>{return result.json() })
.then((project)=>{
if(project === "error"){
alert("Error")
}else{
this.setState({
projectInfo: project,
images: createImages(project)
},function(){
window.initDogma()
})
}
})
}
componentDidMount(){
window.onload = window.initShit()
}
render(){
const {projectInfo,images} = this.state
console.log(projectInfo)
if(!projectInfo){
return(<h1>. . .</h1>)
}
return(
<div >
<Header />
<SubNav reloadHandler={this.reloadHandler} />
<div className="content full-height no-padding">
<div className="fixed-info-container">
<Link to="/portfolio"><button className="goBackBtn">Desarrollos</button></Link>
<h3>{projectInfo.project.project}</h3>
<div className="separator" />
<div className="clearfix" />
<p>
{projectInfo.project.address}
</p>
<span className="project-status">{projectInfo.project.status}</span>
<h4>Características</h4>
<Details price={projectInfo.project.price} features={projectInfo.project.features} />
<Link className=" btn anim-button trans-btn transition fl-l" to={"/contact/?project="+projectInfo.id}>
<span>Informes</span>
<i className="fa fa-eye" />
</Link>
</div>
{/* fixed-info-container end*/}
{/* resize-carousel-holder*/}
<div className="resize-carousel-holder vis-info gallery-horizontal-holder">
{/* gallery_horizontal*/}
<div
id="gallery_horizontal"
className="gallery_horizontal owl_carousel"
>
{
images.map((img,index)=>{
return (
<div key={index}className="horizontal_item">
<div className="zoomimage">
<img src={img} className="intense" alt="" />
<i className="fa fa-expand" />
</div>
<img src={img} alt="" />
<div className="show-info">
<span>Info</span>
<div className="tooltip-info">
<h5>Imagen de muestra</h5>
<p>
Imagen del desarrollo
</p>
</div>
</div>
</div>
)
})
}
</div>
{/* resize-carousel-holder*/}
{/* navigation */}
<div className="customNavigation">
<a href="/" className="prev-slide transition">
<i className="fa fa-angle-left" />
</a>
<a href="/" className="next-slide transition">
<i className="fa fa-angle-right" />
</a>
</div>
{/* navigation end*/}
</div>
{/* gallery_horizontal end*/}
</div>
<Footer />
</div>
)
}
}
export default Project
I'm currently looking how to fix this, but if someone could give me an advice or the origin of the issue would be really helpful.
By the time your question was posted, there was an issue open at reactjs github repo talking about something similar. It is now solved, but you may want to read the article.
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.
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}>