Parent and child relations in React - reactjs

I'm having some issues with parsing refs to child classes using ReactJS
Here is my main class where all my refs are located :
class App extends Component {
render() {
return (
<div className="App">
<Navbar />
<Title content="I am Tristan Vermeesch" />
<hr />
<Bio />
<Introduction ref={(Introduction) => { this.introref = Introduction; }} />
<Timeline ref={(Timeline) => { this.timelineref = Timeline }} />
<Projects ref={(Projects) => { this.projectsref = Projects }} />
<Skills ref={(Skills) => { this.skillsref = Skills }} />
<Certificates ref={(Certificates) => { this.certifref = Certificates }} />
<Download ref={(Download) => { this.downloadref = Download }} />
<Contact ref={(Contact) => { this.contactref = Contact }} />
</div>
);
}
}
I want that a Child component in my <Navbar /> retrieves the ref to make it scroll down using react-scroll-to-component. Here is my Navbar class :
class Navbar extends Component {
render() {
return (
<div className="navbar" >
<Route path="/textversion" component={TextVersion} />
<Navitem dName={"Text Version"} url={"textversion"} />
<Navitem dName={"Contact"} url={"contact"} />
<Navitem dName={"Resume"} url={"resume"} />
<Navitem dName={"Certificates"} url={"certificates"} />
<Navitem dName={"Skills"} url={"skills"} onClick={() => scrollToComponent(this.skillsref, { duration: 1600 })} />
<Navitem dName={"Projects"} url={"projects"} />
<Navitem dName={"Life"} url={"life"} />
<Navitem dName={"Me"} url={"me"} />
</div>
)
}
}
You can see the onclick function there, it works in the main class but how can I get all the refs from the parent class?

Try something like this:
You have to define this in your app class
introref =React.createRef()
timelineref = React.createRef()
projectsref = React.createRef()
skillsref = React.createRef()
certifref = React.createRef()
downloadref = React.createRef()
contactref = React.createRef()
and use like this:
<Introduction ref={this.introref} />
<Timeline ref={this.timelineref} />
<Projects ref={this.projectsref} />
<Skills ref={ this.skillsref} />
<Certificates ref={this.certifref} />
<Download ref={this.downloadref } />
<Contact ref={this.contactref} />
and yes you have to crate props in your NavBar:
<Navbar
introref={this.introref}
timelineref={this.timelineref}
projectsref={this.projectsref}
skillsref={this.skillsref}
certifref={this.certifref}
downloadref={this.downloadref }
contactref{this.contactref}
/>
And inside NavBar you have to use like this:
const { introref,timelineref,projectsref,skillsref,certifref,downloadref,contactref } = this.props
and you can us the ref like call
introref.current
timelineref.current
so in your code something like:
<Navitem dName={"Skills"} url={"skills"} onClick={() => scrollToComponent(skillsref.current, { duration: 1600 })} />
I hope it will work

Related

How to send multiple elements as React children and position individually where you want

The structure should look like this:
<Modal>
<Header />
<Body />
<Footer />
</Modal>
The output should look like this
<div>
<header>
<Header />
</header>
<main>
<Body />
</main>
<footer>
<Footer />
</footer>
</div>
You can select the passed children by their index and position them.
Here's how to achieve the solution,
const Modal = ({children}) => {
return (
<div>
<header>
{ children[0] }
</header>
<main>
{ children[1] }
</main>
<footer>
{ children[2] }
</footer>
</div>
)
}
We have this option to specify different spaces for multiple components. In React, we don't but this action can be done by passing props. Like this:
<MyComponent
headerComponent={<Header />}
bodyComponent={<Body />}
footerComponent={<Footer />}
>
</div>
And in MyComponent:
const MyComponent = (props) => {
return (
<div>
{props.headerComponent}
{props.bodyComponent}
{props.footerComponent}
</div>
)
}
const Modal = ({ children }) => {
return (
<React.Fragment>
<header>{children[0]}</header>
<main>{children[1]}</main>
<footer>{children[2]}</footer>
</React.Fragment>
)};
or
const Modal = ({ children }) => {
return (
<>
<header>{children[0]}</header>
<main>{children[1]}</main>
<footer>{children[2]}</footer>
</>
)};
which does the same things.

Trigger a slide right animation after rendering a component through history.push

I have this component that redirects the user upon a click, to another path, associated with a component.
return (
<Item
key={id}
onClick={() =>
history.push({
pathname: '/path/login',
state: {
requiredAction: name,
},
})
}
description={description}
/>
);
my login component as follows:
export default withRouter(function FormCard(props) {
let { location } = props;
return (
<div className="text-center">
{location.state.imageData && (
<Image className={location.state.imageData} />
)}
<div className="heading mb-5 pt-2">
<FormattedMessage defaultMessage="Access your account" />
)}
</div>
<div>
<input
className="email-form"
type="email"
inputMode="email"
onChange={changeEmail}
/>
</div>
</div>
);
});
Route is defined as follows:
<Route
exact
path="/path/login"
render={() => <FormCard {...this.props} />}
/>
==========================
Is is possible that I add some logic on history.push, after the initial click that triggers an animation to slide right the login component, instead of simply displaying it?
Yes, you can add some logic on history.push. I suggest that you listen in your /path/login for the passed state, like this:
Example Component (In your case the /path/login one):
const App = (props) => {
const {location} = props;
useEffect(()=>{
if(location.state.PASSED_VAL){
// Do something
}
},[location.state])
}
return (...)
}

Cannot Read image of undefined in React app

I'm use the filter method to pick-out one featured item in an array and use that to render it's state in my Home Component. I'm using the filter method in the MainComponent, passing that to the Home Component, where I want the AddCard functional component to render. I'm getting the error message of "cannot read image of undefined" so I'm assuming I'm doing something wrong in passing my props.
MainComponent.js
class Main extends Component{
constructor(props){
super(props);
this.state={
whyfastpack: WHYFASTPACK
};
}
render(){
const LandingPage =()=>{
return (
<Landing />
);
};
const HomePage=()=>{
return (
<Home
lightweight={this.state.whyfastpack.filter(lightweight => lightweight.featured)[0]}
/>
);
};
return(
<div>
<Header />
<Switch>
<Route exact path='/' component={LandingPage} />
<Route path ='/home' component={HomePage} />
HomeComponent.js
...
</div>
<div className='col-md m-1'>
<AddCard />
</div>
</div>
....
function RenderCard({ item }) {
return (
<Card>
<CardImg src={this.image} alt={item.name} />
<CardBody>
<CardTitle>{item.name}</CardTitle>
<CardText>{item.comment}</CardText>
</CardBody>
</Card>
);
}
function AddCard(props) {
return (
<div className="container">
<div className="row">
<div className="col-md m-1">
<RenderCard item={props.lightweight} />
</div>
</div>
</div>
);
}
whyFastPack.js
export const WHYFASTPACK = [
{
id: 0,
image: 'images/pnw.jpg',
name: 'Reduce Weight',
comment: 'Carry only what you need for the day, not a month! With fast-packing you only need to bring enough to get you through each day!',
featured: true,
}
]
You neglected to pass a lightweight prop to AddCard from HomeComponent.
<div className='col-md m-1'>
<AddCard lightweight={this.props.lightweight} />
</div>

props in app does not work in other component

Currently I'm working on a project for a customer. I am building my frontend in ReactJs and I should use a loggedIn check. While I'm loggedIn I want to change my button Log Out. And by a product I want to show in cart, but it does not show anything at all by loggedIn: true in App.js
Code:
App.js
state = {
name: "Tapijtboerderij",
winkelmand: 0,
gebruiker: null,
product: null,
loggedIn: true
}
render() {
return (
<div className="App" >
<Menu props={this.state} />
}
Menu.js (made in React.Router)
A line of code to router to component.
import React from 'react'
import { BrowserRouter as Router, Route } from "react-router-dom";
import LinkTo from './link';
import Index from "../pages/index";
import Tapijt from "../pages/tapijt";
import Vloeren from "../pages/vloeren";
import Zonwering from "../pages/zonwering";
import Gordijnen from "../pages/gordijnen";
import Contact from "../pages/contact";
import Login from "../pages/login";
import Product from "../pages/product";
import Page404 from "../pages/404";
import AlgemeneVoorwaarden from "../voorwaarden/algemene-voorwaarden";
import CookieBeleid from "../voorwaarden/cookie-beleid";
import PrivacyBeleid from "../voorwaarden/privacy-beleid";
import Sitemap from "../voorwaarden/sitemap";
import logo from "../logo/logo.jpg";
import Button from "./button";
export default class Menu extends React.Component {
constructor(props) {
super(props);
this.state = {
collapsed: false,
widthOverlay: 0
}
}
collapseMenu = () => {
let strepen = document.querySelectorAll(".streep");
if (this.state.collapsed === false) {
strepen[0].style.transform = "rotate(-45deg)";
strepen[0].style.marginTop = "7px";
strepen[1].style.display = "none";
strepen[2].style.transform = "rotate(45deg)";
strepen[2].style.marginTop = "-7px";
this.setState({
collapsed: !this.state.collapsed,
widthOverlay: "60%"
});
} else {
strepen[0].style.transform = "rotate(0deg)";
strepen[0].style.marginTop = "0";
strepen[1].style.display = "block";
strepen[2].style.transform = "rotate(0deg)";
strepen[2].style.marginTop = "0";
this.setState({
collapsed: false,
widthOverlay: 0
})
}
}
render() {
return (
<Router>
<nav className="menu">
<div className="container">
<a href="/" className="brand-logo to-left">
<img src={logo} className={"menu-logo"} alt={"logo bedrijf"} />
</a>
<div className={"links to-right menu-laptop"}>
<div className={"menu-links-laptop"}>
<LinkTo to="/" name={"Home"} />
<LinkTo to="/src/pages/tapijt" name={"Tapijt"} />
<LinkTo to="/src/pages/vloeren" name={"Vloeren"} />
<LinkTo to="/src/pages/zonwering" name={"Zonwering"} />
<LinkTo to="/src/pages/gordijnen" name={"Gordijnen"} />
<LinkTo to="/src/pages/contact" name={"Contact"} />
{this.props.loggedIn ? <Button link={"/src/pages/login"} buttonName={"Log uit"} /> : <Button link={"/src/pages/login"} buttonName={"Log in"} />}
</div>
</div>
</div>
</nav>
<div className="sidenav" id="mobile-demo" style={{
width: `${this.state.widthOverlay}`
}}>
<div className={"menu-icon"} onClick={this.collapseMenu}>
<div className={"strepen"}>
<div className={"streep"} />
<div className={"streep"} />
<div className={"streep"} />
</div>
</div>
<div className={"links-mobile"}>
<LinkTo to="/" name={"Home"} />
<LinkTo to="/src/pages/tapijt" name={"Tapijt"} />
<LinkTo to="/src/pages/vloeren" name={"Vloeren"} />
<LinkTo to="/src/pages/zonwering" name={"Zonwering"} />
<LinkTo to="/src/pages/gordijnen" name={"Gordijnen"} />
<LinkTo to="/src/pages/contact" name={"Contact"} />
<LinkTo to="/src/pages/login" name={"Log in"} />
</div>
</div>
<Route path="/" exact component={Index} />
<Route path="/src/pages/tapijt" component={<Tapijt loggedIn={this.props.loggedIn} />} />
<Route path="/src/pages/vloeren" component={Vloeren} />
<Route path="/src/pages/zonwering" component={Zonwering} />
<Route path="/src/pages/gordijnen" component={Gordijnen} />
<Route path="/src/pages/contact" component={Contact} />
<Route path="/src/pages/login" component={Login} />
<Route path="/src/pages/product" component={Product} />
<Route path="/src/pages/404" component={Page404} />
<Route path="/src/voorwaarden/algemene-voorwaarden" component={AlgemeneVoorwaarden} />
<Route path="/src/voorwaarden/cookie-beleid" component={CookieBeleid} />
<Route path="/src/voorwaarden/privacy-beleid" component={PrivacyBeleid} />
<Route path="/src/voorwaarden/sitemap" component={Sitemap} />
</Router >
);
}
}
Tapijt.js
render() {
return (
<div className={"container"}>
<h1 className={"header"}>Tapijten</h1>
<div className={"parent"}>
<div className={"flex"}>
{tapijten.map((tapijt, identifier) =>
<Card key={identifier}
photo={TapijtImg}
productHeader={tapijt}
productContent={"Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of \"de Finibus Bonorum et Malorum\" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, \"Lorem ipsum dolor sit amet..\", comes from a line in section 1.10.32."}
link={"./product"}
buttonName={"Ga naar Product"}
loggedIn={this.state.loggedIn} />)}
</div>
</div>
</div>
)
}
Product.js
import React from 'react';
import ProductImage from "../images/tapijt.jpg";
import Button from "../components/button";
let productSpecifications = [["Lengte: ", 1200], ["Breedte: ", 1000], ["Soort: ", "Hoogpolig
saxony"], ["Prijs per vierkante M(2): ", 4.85]];
class Product extends React.Component {
constructor(props) {
super(props);
this.state = {
data: productSpecifications
}
}
render() {
return (
<div className={"container top-40"}>
<div className={"flex half-om-half"}>
<div className={"product-photo"}>
<img src={ProductImage} className={"product-img"} alt={"product foto"} />
</div>
<div className={"product-info"}>
<h1 className={"product-header"}>Product Header can Kania</h1>
<p>
Is it possible to use CSS pseudo-classes to select even and odd instances of list items?
I'd expect the following to produce a list of alternating colors, but instead I get a list of blue items:
</p>
<h2 className={"product-price"}>679,-</h2>
{/*{this.props.loggedIn ? <Button link={"#"} buttonName={"In Winkelmand"} /> : ""}*/}
{this.props.loggedIn ? <Button backgroundColor={"var(--success-color)"} color={"var(--white)"} link={"#"} buttonName={"In Winkelmand"} /> : ""}
</div>
</div>
<div className={"product-specifications"}>
<h2>Details</h2>
<table>
<tbody>
{this.state.data.map((data) => <ul>{data}</ul>)}
</tbody>
</table>
</div>
</div>
)
}
}
export default Product;
Thank you in advance
First of all your Route is wrong.
<Route path="/src/pages/tapijt" component={<Tapijt loggedIn={this.props.loggedIn} />} />
It should be
<Route path="/src/pages/tapijt" render={(props) => (<Tapijt loggedIn={this.props.loggedIn} {...props}/>)}/>
Unless you handle it somewhere else not showing in current code snippet, you pass the loggedIn value to Tapijt component but you don't handle it somehow. you are using a state property loggedIn.
Maybe this
buttonName={"Ga naar Product"}
loggedIn={this.state.loggedIn} />)}
should be this?
buttonName={"Ga naar Product"}
loggedIn={this.props.loggedIn} />)}
just to be on the same page.
You are passing your Props Object called state from App.js to the Menu Component.
So I assume that you check for the this.props.state inside the Menu Component right ?
<Route path="/src/pages/tapijt" component={<Tapijt loggedIn={this.props.loggedIn} />} />
Where does this line of code comes from ?
Right now I'm missing the context, where you pass your Props ( loggedIn: true / false ) to your Product.js
It would be great if you could share the could over CodePen or JSFiddle for e.g.
EDIT:
You can try doing it like this:
// Inside of App.js
const userInfo = {
name: "Tapijtboerderij",
winkelmand: 0,
gebruiker: null,
product: null,
loggedIn: true
}
render() {
return (
<div className="App" >
<Menu {...userInfo} />
</div>
}
// Inside of Menu.js
export default class Menu extends React.Component {
...
constructor(props) {
super(props);
this.state = {
collapsed: false,
widthOverlay: 0
}
}
...
render() {
return(
<Router>
<nav className="menu">
<div className="container">
<a href="/" className="brand-logo to-left">
<img src={logo} className={"menu-logo"} alt={"logo bedrijf"} />
</a>
<div className={"links to-right menu-laptop"}>
<div className={"menu-links-laptop"}>
<LinkTo to="/" name={"Home"} />
<LinkTo to="/src/pages/tapijt" name={"Tapijt"} />
<LinkTo to="/src/pages/vloeren" name={"Vloeren"} />
<LinkTo to="/src/pages/zonwering" name={"Zonwering"} />
<LinkTo to="/src/pages/gordijnen" name={"Gordijnen"} />
<LinkTo to="/src/pages/contact" name={"Contact"} />
{this.props.loggedIn ? <Button link={"/src/pages/login"} buttonName={"Log uit"} /> : <Button link={"/src/pages/login"} buttonName={"Log in"} />}
</div>
</div>
</div>
</nav>
...
</Router>
)
}
...
}
// Inside of Product.js
class Product extends React.Component {
constructor(props) {
super(props);
this.state = {
data: productSpecifications
}
}
...
render() {
return(
...
{this.props.loggedIn ? <Button backgroundColor={"var(--success-color)"} color={"var(--white)"} link={"#"} buttonName={"In Winkelmand"} /> : ""}
...
)
}
}
```
By using the Spread Attributes like so: `...userInfoà it also make it easy to pass unnecessary props to components.
I hope it helps you.

React with FlowRouter: How to show/hide component based on route

I have a Meteor application that I'm developing using React and I do my routing using FlowRouter. My main AppContainer for the project has a bunch of components, one of them being the footer.
class AppContainer extends Component {
render() {
return(
<div className="hold-transition skin-green sidebar-mini">
<div className="wrapper">
<Header user={this.props.user} />
<MainSideBar />
{this.props.content}
<Footer />
<ControlSideBar />
<div className="control-sidebar-bg"></div>
</div>
</div>
)
}
}
I have a few routes that go to various chat rooms:
Eg.
/chatroom/1
/chatroom/2
/chatroom/3
Is there a way for me to hide the <Footer /> component if the route is a /chatroom/<anything>?
You can maybe do a conditional rendering by checking the current path.
If the <anything> part (I assume it is a parameter) after the /chatroom/ is not important, and if you do not have any other routing that starts with chatroom, you can try this one:
const currentPath = window.location.pathname
{!currentPath.includes('chatroom') ? <Footer /> : null }
So your code would look like this:
class AppContainer extends Component {
render() {
currentPath = window.location.pathname
return(
<div className="hold-transition skin-green sidebar-mini">
<div className="wrapper">
<Header user={this.props.user} />
<MainSideBar />
{this.props.content}
{!currentPath.includes('chatroom')
? <Footer />
: null }
<ControlSideBar />
<div className="control-sidebar-bg"></div>
</div>
</div>
)
}
}
If <anything> part is important and/or you have other routes that starts with chatroom, you can first get the parameter of the route with
const param = FlowRouter.getParam('someParam');
and then do the conditional rendering by checking if the current path contains the chatroom/:param like this:
const currentPath = window.location.pathname
{!currentPath.includes(`chatroom/${param}`) ? <Footer /> : null }
So your code would look like this
class AppContainer extends Component {
render() {
const currentPath = window.location.pathname
const param = FlowRouter.getParam('someParam');
return(
<div className="hold-transition skin-green sidebar-mini">
<div className="wrapper">
<Header user={this.props.user} />
<MainSideBar />
{this.props.content}
{!currenPath.includes(`chatroom/${param}`)
? <Footer />
: null }
<ControlSideBar />
<div className="control-sidebar-bg"></div>
</div>
</div>
)
}
}
You can also use the following syntax below. It accomplishes the same thing as the first example provided by Cagri Yardimci.
{ !currentPath.includes('chatroom') && <Footer /> }

Resources