onClick inside mapped object JSX for React NextJS not working - javascript

I have a component :
import React, { Component } from 'react';
import ImageItem from '../components/ImageItem';
class ImageList extends Component {
handleClick() {
console.log('Testing testing...'); // ---> This is not working.
}
render() {
const images = this.props.images.map(image => {
return (
<ImageItem
onClick={this.handleClick}
key={image.id}
image={image.src}
title={image.title}
/>
);
});
return (
<div className="image-list" ref={el => (this.el = el)}>
{images}
</div>
);
}
}
export default ImageList;
However, my onClick is not console logging anything out when it is inside the mapped function.
This is my ImageItem component:
import React, { Component } from 'react';
class ImageItem extends Component {
render() {
return (
<a href="#">
<img
className="portfolio-image"
src={this.props.image}
alt={this.props.title}
/>
</a>
);
}
}
export default ImageItem;
What am I doing wrong here?

You are not assigning the click handler to your component it should look like this :
class ImageItem extends Component {
render() {
return (
<a href="#" onClick={this.props.onClick}>
<img
className="portfolio-image"
src={this.props.image}
alt={this.props.title}
/>
</a>
);
}
}
export default ImageItem;

Related

React Pass const from file to another

I have two page with same logic but different content and i want to use the same object but parse different json content.
Projects and Experience page use the same ProjectList and Project. I want to pass different content to Projects.js and Experience.js
Project:
import React, {Component} from 'react';
import Navigation from "../components/Nagivation";
import ProjectList from "../components/experience/ProjectList";
import { portfolioData } from '../data/portfolioData';
export default class Projects extends Component {
state = {
projects:portfolioData
};
render() {
let {projects} = this.state;
return (
<div className="portfolio">
<Navigation/>
{
<ProjectList
item={projects}
/>
}
</div>
);
}
};
ProjectList
import React, {Component} from 'react';
import Project from "./Project";
export default class ProjectList extends Component {
render() {
console.log(this.props.item)
let {projects} = this.props.item;
return (
<div className="portfolioContent">
<h3 className="radioDisplay">Test</h3>
<div className="projects">
{
projects.map(item => {
return (
<Project
key={item.id}
item={item}
/>
)
})
}
</div>
</div>
);
}
}
I have Uncaught TypeError: Cannot read properties of undefined (reading 'map') on the line <div className="projects">
Project.js
import React, {Component} from 'react';
export default class Project extends Component {
state = {
showInfo: false
}
handleInfo = () => {
this.setState({
showInfo:!this.state.showInfo
})
}
render() {
let {name, periode, info, picture} = this.props.item
return (
<div className="project">
<h5>{periode}</h5>
<h3>{name}</h3>
<img src={picture} alt="" onClick={this.handleInfo} />
//some stuffs
);
}
}
I don't want to use map, because i want to iterate only in ProjectList.

I'm getting an undefined error in my project made with React

I am sending as a prop an array of objects. When I console.log(this.props) I get the array of objects, but when I try to assign it to a variable it gives me
TypeError:ninjas is undefined
This is how i send the prop
import React from 'react';
import Ninjas from './Ninjas';
class App extends React.Component {
state = {
ninjas:[
{name:"Ryu",age:"20",belt:"black",key:"1"},
{name:"Yoshi",age:"22",belt:"yellow",key:"2"},
{name:"Mario",age:"25",belt:"white",key:"1"}
]
}
render(){
return (
<div>
<h1>My first React App</h1>
<Ninjas list={ this.state.ninjas }/>
</div>
)
}
}
export default App;
And this is how i recibe it
import React from 'react';
class Ninjas extends React.Component {
render(){
const { ninjas } = this.props;
const ninjasList = ninjas.map(ninja => {
return(
<div className="ninja" key={ ninja.key }>
<div>Name: { ninja.name }</div>
<div>Age: { ninja.age }</div>
<div>Belt: { ninja.belt }</div>
</div>
)
})
return (
<div className="ninja-list">
{ ninjasList }
</div>
);
}
}
export default Ninjas;
<Ninjas list={ this.state.ninjas }/>
I suggest you change this to
<Ninjas ninjas={ this.state.ninjas }/>
Otherwise the name would be list in your child component.
In other words the name of the property you use when rendering the component (here in the render function of App) has to correspond to the name you get from the props object in your child component (here your child component is Ninjas).
You are passing ninjas in your Ninjas component <Ninjas list={ this.state.ninjas }/> using list props. So, you should be using this const { list } = this.props; instead of const { ninjas } = this.props; in your Ninjas Component.
import React from 'react';
class Ninjas extends React.Component {
render(){
const { list } = this.props;
const ninjasList = list.map(ninja => {
return(
<div className="ninja" key={ ninja.key }>
<div>Name: { ninja.name }</div>
<div>Age: { ninja.age }</div>
<div>Belt: { ninja.belt }</div>
</div>
)
})
return (
<div className="ninja-list">
{ ninjasList }
</div>
);
}
}
export default Ninjas;

How to change component inside of render with a button click?

I'm new at programming at all especially in ReactJS. Actually I'm running into a problem.
I just wanna change the page. As simple as it sounds for me it is a 2 day Google-Search-Nothing-Found-Adventure without fun.
I made a component called <Frontpage />
It renders directly in the beginning but I want to change it with a click on a button.
This is my code:
import React from 'react';
import './App.css';
import Frontpage from './Frontpage'
import Question from './components/Question'
class App extends React.Component {
constructor() {
super()
this.state = {
showComponent: true,
}
}
handleClick() {
if (this.state.showComponent) {
return <Question />
} else {
console.log("Something went wrong!")
}
// console.log("The button was clicked!")
// document.getElementById('page')
// document.getElementsByClassName('App-Header')
}
render() {
return (
<div className="App">
<header className="App-header">
<div id="page">
<Frontpage />
</div>
<button id="button" onClick={this.handleClick}>Los geht's</button>
</header>
</div>
);
}
}
export default App;
When I click it, it always says: "TypeError: Cannot read property 'state' of undefined"
I tried a lot but nothing worked.
Try something like this. Change you handleClick function to an arrow function and render the component based on the state.
Update: notice that i have used a Fragment to wrap the button and Question elements/components
import React,{Fragment} from 'react';
import './App.css';
import Frontpage from './Frontpage'
import Question from './components/Question'
class App extends React.Component {
constructor() {
super()
this.state = {
showComponent: false,
}
}
handleClick =()=> {
this.setState({showComponent:true})
}
render() {
return (
<div className="App">
<header className="App-header">
<div id="page">
{this.state.showComponent? <Fragment><Question /><button id="button" onClick={this.handleClick}>Los geht's</button></Fragment> : <Frontpage /> }
</div>
</header>
</div>
);
}
}
export default App;
You have to bind the handleClick to your class component or in other case, use an arrow function:
To bind the method at the bottom of your state inside the constructor add this :
this.handleClick = this.handleClick.bind(this);
To use the arrow function change the syntax of your method as:
this.handleClick = () => {
if (this.state.showComponent) {
return <Question />
} else {
console.log("Something went wrong!")
}
}
import React from 'react';
import './App.css';
import Frontpage from './Frontpage'
import Question from './components/Question'
class App extends React.Component {
constructor() {
super()
// Start with a hide component
this.state = {
showComponent: false,
}
// Binding your function
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
const { showComponent } = this.state;
// Use state to trigger a re-render
this.setState({
showComponent: !showComponent;
})
}
render() {
const { showComponent } = this.state;
return (
<div className="App">
<header className="App-header">
<div id="page">
{
// Conditionally render a component
showComponent
? (<Question />)
: (<Frontpage />)
}
</div>
<button id="button" onClick={this.handleClick}>Los get's</button>
</header>
</div>
);
}
}
export default App;
Try this one.
import Question from './components/Question'
class App extends React.Component {
constructor() {
super()
this.state = {
showComponent: true,
}
}
handleClick() {
this.setState({ showComponent: true });
}
render() {
const { showComponent } = this.state;
return (
<div className="App">
<header className="App-header">
<div id="page">
<Frontpage />
</div>
{ showComponent ? <Question /> : null }
<button id="button" onClick={this.handleClick.bind(this)}>Los geht's</button>
</header>
</div>
);
}
}
export default App;

how can i call react state different js

i want to change state different js but i can not , i have a sidebar.js with react-burger-menu
i want to call and change toggleMenu state in header.js
When I click the menu link, i want to toggle react-burger-menu but different js. this is not working.
sidebar.js
import React from "react";
import PropTypes from "prop-types";
import { reveal as Menu } from "react-burger-menu";
import * as FontAwesome from "react-icons/lib/fa";
export default class SidebarMenu extends React.Component {
constructor (props) {
super(props)
this.state = {
menuOpen: false
}
}
handleStateChange (state) {
this.setState({menuOpen: state.isOpen})
}
closeMenu () {
this.setState({menuOpen: false})
}
toggleMenu () {
this.setState({menuOpen: !this.state.menuOpen})
}
render () {
return (
<div>
<Menu
isOpen={this.state.menuOpen}
onStateChange={(state) => this.handleStateChange(state)}
>
// menu content
</Menu>
</div>
</div>
)
}
}
header.js have link for react-burger-menu
import React from 'react';
import PropTypes from 'prop-types';
import SidebarMenu from "../SidebarMenu";
export default class Header_Video extends React.Component {
render() {
return (
<Container>
<Row>
<Col md={5} sm={12} xs={12} className="text-left mobile-right">
<div className="bar__module">
<a onClick={this.toggleMenu}>Menu</a>
</div>
</Col>
</Row>
</Container>
);
}
}
thanks for help
note: i have a app.js all files import. I want to run toggleMenu in header.js
app.js
const TemplateWrapper = ({ children }) => (
<div id="outer-container">
<SidebarMenu />
<main id="page-wrap" className="page-wrap">
<HeaderVideo /> {children()}
<Footer />
</main>
</div>
);
menuOpen should be in a parent state of both components.
Example:
class App extends React.Component {
constructor (props) {
super(props)
this.state = {
menuOpen: false
}
}
closeMenu = () => {
this.setState({menuOpen: false})
}
toggleMenu = () => {
this.setState({menuOpen: !this.state.menuOpen})
}
render() {
return (
<div>
<SidebarMenu isMenuOpen={this.state.menuOpen} toggleMenu={this.toggleMenu} />
<Header toggleMenu={this.toggleMenu} />
</div>
)
}
}
You may have further errors beyond just this, but the glaring error to me is that toggleMenu() is not bound to the constructor.
https://reactjs.org/docs/handling-events.html
try:
import React from "react";
import PropTypes from "prop-types";
import { reveal as Menu } from "react-burger-menu";
import * as FontAwesome from "react-icons/lib/fa";
export default class SidebarMenu extends React.Component {
constructor (props) {
super(props)
this.state = {
menuOpen: false
}
this.toggleMenu = this.toggleMenu.bind(this);
// the above statement binds the function to the object constructor
}
handleStateChange (state) {
this.setState({menuOpen: state.isOpen})
}
closeMenu () {
this.setState({menuOpen: false})
}
toggleMenu () {
this.setState({menuOpen: !this.state.menuOpen})
}
render () {
return (
<div>
<Menu
isOpen={this.state.menuOpen}
onStateChange={(state) => this.handleStateChange(state)}
>
// menu content
</Menu>
</div>
</div>
)
}
}
You'll also want to use an HTML5 button tag instead of a link tag, the correct HTML semantic structure provides a bunch of underlying features and greatly improves accessibility out of the box.
Also, remove the arrow function and pass a reference to the function, not the returned value. This is so react doesn't call the function immediately but stores the function reference to execute upon the click event.
<button onClick={this.toggleMenu}>Menu</button>
// instead of
<a onClick={() => this.toggleMenu()}>Menu</a>
Hope this helps!

Create a list from Array React JS

Im trying to create an array to store my category links and then display them however I'm getting nothing displaying in my DOM. Any help would be appreciated :)
import React from "react";
import { SidebarCategory } from './SidebarCategory';
class SidebarCategories extends React.Component {
constructor() {
super();
this.state = {
categories: []
}
}
componentWillMount() {
this.setState({categories: [
{
id: 1,
icon: "icon",
title: "Home",
},
{
id: 2,
icon: "icon",
title: "Gallery",
}
]});
}
render() {
return (
<ul className="sidebar__categories container-fluid">
{this.state.categories.map(category => {
return (
<SidebarCategory key={category.id} title={category.title} />
)
})};
</ul>
);
}
}
export default SidebarCategories;
edit:
console error:
bundle.js:357 Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in. Check the render method of Sidebar.
in Sidebar (created by App)
in div (created by App)
in App
sidebarCategory.js
import React from "react";
export class SidebarCategory extends React.Component {
render() {
const SidebarCategory = ({ title }) => {
return (<div className="sidebarCategory">{title}</div>);
}
}
}
sidebar.js:
import React from "react";
import { SidebarCategories } from "./SidebarCategories";
export class Sidebar extends React.Component {
render() {
return (
<div className="sidebar col-sm-2">
<div className="row">
<div className="sidebar__header col">
<img alt="Logo" className="img-fluid sidebar__header__logo" src="../resources/img/logo-white.png" />
{'\u00A0'} <h4 className="i-block">Title</h4>
</div>
</div>
<div className="row">
<div className="sidebar__user container-fluid">
<div className="row">
<div className="col-sm-4">
<img alt="User DP" className="sidebar__user__img img-fluid rounded-circle" src="http://via.placeholder.com/100x100" />
</div>
<div className="col-sm-8">
<p><strong>Welcome</strong><br />
Mark Hughes</p>
</div>
</div>
</div>
</div>
<div className="row">
<SidebarCategories />
</div>
</div>
);
}
}
index.js:
import React from "react";
import { render } from "react-dom";
import Sidebar from "./components/sidebar";
import Content from "./components/content";
class App extends React.Component {
render() {
return (
<div className="row">
<Sidebar />
<Content />
</div>
);
}
}
render(<App className="container-fluid"/>, window.document.getElementById("app"));
import React from "react";
import SidebarCategory from './SidebarCategory';
class SidebarCategories extends React.Component {
constructor() {
super();
this.state = {
categories: []
}
}
componentWillMount() {
this.setState({categories: [
{
id: 1,
title: "Home",
},
{
id: 2,
title: "Gallery",
}
]});
}
render() {
return (
<ul className="sidebar__categories container-fluid">
<SidebarCategory categories={this.state.categories} />
</ul>
);
}
}
export default SidebarCategories;
And add this in your SidebarCategory file:-
import React from "react";
export class SidebarCategory extends React.Component {
render() {
return (
<li className="sidebar__category container-fluid">
<div className="row">
<div className="col-sm-10">
{this.props.categories.map((category, key) =>(
<span key={key}>{category.title}</span>
))}
</div>
</div>
</li>
);
}
}
At the moment you're not iterating over your categories you have held in state, so the first thing is to map over them and provide your sub-component <SidebarCategory> the data it needs; a key from the category id, and the title.
render() {
return (
<ul className = "sidebar__categories container-fluid">
{this.state.categories.map(category => {
return (
<SidebarCategory
key={category.title}
title={category.title}
/>
)
})}
</ul>
);
}
Then your <SidebarCategory> component should return a div (for example) the title of which is filled in from the props that you've provided it.
const SidebarCategory = ({ title }) => {
return <div className="SidebarCategory">{title}</div>
}
export default SidebarCategory;
First in SidebarCategories
import {SidebarCategory}... //with curly braces
Second in Sidebar:
import SidebarCategories from "./SidebarCategories"; //without curly braces
See:
export class SidebarCategory //no default -> import {SidebarCategory} from...
export default SidebarCategories; //with default -> import SidebarCategories from ...
Try these:
index.js
import React from "react";
import { render } from "react-dom";
import Sidebar from "./components/sidebar";
import Content from "./components/content";
class App extends React.Component {
render() {
return (
<div className="row">
<Sidebar />
<Content />
</div>
);
}
}
render(<App className="container-fluid"/>, document.getElementById("app"));
Sidebar.js
import React from "react";
import SidebarCategories from "./SidebarCategories";
class Sidebar extends React.Component {
render() {
return (
<div className="sidebar col-sm-2">
<div className="row">
<div className="sidebar__header col">
<img alt="Logo" className="img-fluid sidebar__header__logo" src="../resources/img/logo-white.png" />
{'\u00A0'} <h4 className="i-block">Title</h4>
</div>
</div>
<div className="row">
<div className="sidebar__user container-fluid">
<div className="row">
<div className="col-sm-4">
<img alt="User DP" className="sidebar__user__img img-fluid rounded-circle" src="http://via.placeholder.com/100x100" />
</div>
<div className="col-sm-8">
<p><strong>Welcome</strong><br />
Mark Hughes</p>
</div>
</div>
</div>
</div>
<div className="row">
<SidebarCategories />
</div>
</div>
);
}
}
export default Sidebar;
SidebarCategory.js
import React from "react";
class SidebarCategory extends React.Component {
render() {
return (
<div className="row">
<div className="col-sm-10">
{this.props.category.title}
</div>
</div>
);
}
}
export default SidebarCategory;
SidebarCategories.js
import React from "react";
import SidebarCategory from './SidebarCategory';
class SidebarCategories extends React.Component {
constructor() {
super();
this.state = {
categories: []
}
}
componentWillMount() {
this.setState({categories: [
{
id: 1,
title: "Home",
},
{
id: 2,
title: "Gallery",
}
]});
}
render() {
let list = this.state.categories.map((category) => {
<li className="sidebar__category container-fluid" key={category.id}><SidebarCategory category={category} /></li>
});
return (
<ul className="sidebar__categories container-fluid">
{list}
</ul>
);
}
}
export default SidebarCategories;
I believe the issue is in your sidebarCategory.js, you created a stateless (arrow function) component inside a stateful component.
since its just a component that render data from its props you can use the stateless/arrow function alone like this.
const SidebarCategory = ({ title }) => {
return (<div className="sidebarCategory">{title}</div>);
}
export default SidebarCategory; // this way its exported as default component, import it without using curly brackets (import SidebarCategory from './SidebarCategory';
// OR
export SidebarCategory; // this way its exported as non-default component, import it using the curly brackets (import {SidebarCategory} from './SidebarCategory';

Categories

Resources