TypeError: Cannot read properties of undefined (reading 'map') I'm getting error in these lines - reactjs

import React, { Component } from 'react'
import NewsItem from './NewsItem'
import { Spinner } from './Spinner';
import PropTypes from 'prop-types'
export class News extends Component {
static defaultProps = {
country : 'in',
pageSize : 8,
category: 'General'
}
static propTypes = {
country : PropTypes.string,
pageSize : PropTypes.number,
category: PropTypes.string
}
constructor() {
super();
this.state ={
articles: [],
loading: true,
page: 1
}
}
async updateNews(){
const url = `https://newsapi.org/v2/top-headlines?country=${this.props.country}&category=${this.props.category}&apikey=dbe57b028aeb41e285a226a94865f7a7&page=${this.state.page}&pageSize=${this.props.pageSize}`;
this.setState({ loading: true });
let data = await fetch(url);
let parsedData = await data.json()
this.setState({
articles: parsedData.articles,
totalResults: parsedData.totalResults,
loading: false
})
}
async componentDidMount(){
this.updateNews();
}
handelPreviousClick = async()=>{
this.setState({page : this.state.page - 1});
this.updateNews();
}
handelNextClick = async()=>{
this.setState({ page: this.state.page + 1});
this.updateNews();
}
render(){
return (
<div>
<div className='container my-3'>
<h1 className='text-center' style={{color: "#404040"}}><b>THENewsWorld</b> - Top Headlines</h1>
{this.state.loading && this.state.loading && <Spinner/>}
**<div className="row">
{!this.state.loading && this.state.articles.map((element)=>{**
return <div key={element.url} className="col-md-4">
<NewsItem key={element.url} title={element.title?element.title.slice(0,40):""} description={element.description?element.description:""} imageUrl={element.urlToImage} newsUrl={element.url} author={element.author} date={element.publishedAt} source={element.source.name}/>
</div>
})}
</div>
</div>
<div className='container d-flex justify-content-between'>
<button disabled={this.state.page<=1} type="button" className="btn btn-dark" onClick={this.handelPreviousClick}>← Previous</button>
<button disabled={this.state.page + 1> Math.ceil(this.state.totalResults/this.props.pageSize)} type="button" className="btn btn-warning" onClick={this.handelNextClick}>Next →</button>
</div>
</div>
)
}
}
I'm getting error in these bold lines and my code work properly but suddenly it start giving these errors....

Related

Cannot read property 'key' of undefined react

Home.js component
import React, { Component } from 'react';
import axios from 'axios';
import styles from './home.module.css';
import TurnArrow from '../../assets/images/turn.svg';
import LoadingGif from '../../assets/images/loading.gif';
import SearchBox from '../SearchBox/SearchBox';
import RepoItem from '../RepoItem/RepoItem';
class Home extends Component {
constructor(props) {
super(props)
this.state = {
repos: [],
inputValue: "",
isEmptySearch: false,
isLoading: false,
per_page: 100,
limit: 10,
total_count: null,
showMore: true,
index: 10,
dataLoaded: false,
reposLength: null
}
this.myRef = React.createRef();
this.updateInputValue = this.updateInputValue.bind(this);
this.fetchRepos = this.fetchRepos.bind(this);
this.handleClick = this.handleClick.bind(this);
this.handleKeyPress = this.handleKeyPress.bind(this);
}
scrollToMyRef() {
window.scrollTo(0, this.myRef.current.offsetTop);
}
updateInputValue(e) {
this.setState({
inputValue: e.target.value
});
}
fetchRepos() {
if(this.state.inputValue.trim() === "" || this.state.inputValue.trim() === null) {
return this.setState({ isEmptySearch: true});
}
this.setState({
isEmptySearch: false,
isLoading: true
});
axios.get(`https://api.github.com/search/repositories?q=${this.state.inputValue}&per_page=100`)
.then(response => {
this.setState({
total_count: response.data.total_count,
repos: response.data.items,
isLoading: false,
dataLoaded: true,
reposLength: response.data.items.length
})
return this.scrollToMyRef();
})
.catch(err => console.log(err));
}
handleClick() {
this.fetchRepos();
}
handleKeyPress(e) {
if(e.key === "Enter") {
this.fetchRepos();
}
return
}
render() {
let { repos, isEmptySearch, total_count, isLoading } = this.state;
return (
<>
<header className={styles.hero}>
<div className="container">
<div className={styles.innerHero}>
<div>
<h1>Welcome to GIT M<span>EƎ</span>T</h1>
<p>Discover millions of github repositories <br></br>right here, right now.</p>
<p>Start by using the search box on the right.</p>
</div>
<div className={styles.searchBox}>
<SearchBox>
<img src={TurnArrow} alt="arrow pointing to search button" />
<h1>Search Repos</h1>
<input onKeyPress={this.handleKeyPress} onChange={this.updateInputValue} type="text" name="search" id="search" placeholder="E.g. 'ultra amazing html h1 tag...'" autoComplete="off" required />
<button disabled={ isLoading ? true : false } onClick={this.handleClick}>{ isLoading ? <img src={LoadingGif} alt="loading..." /> : "Search" }</button>
{ isEmptySearch ? <p className={styles.errorMessage}>Please enter something first!</p> : "" }
</SearchBox>
</div>
</div>
</div>
</header>
<main>
{this.state.dataLoaded ? <RepoItem ref={this.myRef} total_count={total_count} repos={repos}/> : "" }
<button className={styles.loadMore}>Load More</button>
</main>
</>
);
}
}
export default Home;
RepoList component
import React, { useState, useEffect } from 'react'
import styles from './repo_item.module.css';
import Footer from '../Footer/Footer';
const RepoList = React.forwardRef((props, ref) => {
const [repos, setRepos] = useState([props.repos]);
useEffect(() => {
setRepos(props.repos);
}, [props.repos]);
return (
<>
<div className="container">
<div className={styles.infoWrap}>
<h2>Results</h2>
<p>Found {props.total_count} results</p>
</div>
<div ref={ref} className={styles.repoWrap}>
{repos.length > 0 ? repos.map((item,index) => {
console.log(item);
return (
<div key={index} className={styles.repoItem}>
<div className={styles.userProfile}>
</div>
{ item.name && item.name.length > 20 ? item.name.substring(0,20) + "..." : item.name }
{ item.license.key }
</div>
);
}) : ""}
</div>
</div>
<Footer />
</>
);
})
export default RepoList;
Why... item.license.key doesnt work but item.name works.............help.
I suppes I messsed up with the connection between Home and repo component, But cannot see the error my self. Thats why I am posting it here, maybe someone will notice the problem faster.
Thank you for in advance, I have tried checking for item and its contents but I get same error everytime.
After finding a lot issue is not in code, data you are getting from API e.g https://api.github.com/search/repositories?q=bootstrap&per_page=100
license property is null so you are getting issue.
check null condition
{item.license && item.license.key}
API Call Response:
{
"total_count":276072,
"incomplete_results":false,
"items":[
{
"id":2126244,
"node_id":"MDEwOlJlcG9zaXRvcnkyMTI2MjQ0",
"name":"bootstrap",
.....
"license":{
"key":"mit",
"name":"MIT License",
"spdx_id":"MIT",
"url":"https://api.github.com/licenses/mit",
"node_id":"MDc6TGljZW5zZTEz"
},
......
},
{
"id":5689093,
"node_id":"MDEwOlJlcG9zaXRvcnk1Njg5MDkz",
"name":"android-bootstrap",
.....
"license":null,
.....
}
]
}

Toggle class only on one element, react js

I`m changing class after clicking and it works.
The problem is that, classes change simultaneously in both elements and not in each one separately. Maybe someone could look what I'm doing wrong. Any help will be useful.
import React, { Component } from "react";
class PageContentSupportFaq extends Component {
constructor(props) {
super(props);
this.state = {
isExpanded: false
};
}
handleToggle(e) {
this.setState({
isExpanded: !this.state.isExpanded
});
}
render() {
const { isExpanded } = this.state;
return (
<div className="section__support--faq section__full--gray position-relative">
<div className="container section__faq">
<p className="p--thin text-left">FAQ</p>
<h2 className="section__faq--title overflow-hidden pb-4">Title</h2>
<p className="mb-5">Subtitle</p>
<div className="faq__columns">
<div
onClick={e => this.handleToggle(e)}
className={isExpanded ? "active" : "dummy-class"}
>
<p className="mb-0">
<strong>First</strong>
</p>
</div>
<div
onClick={e => this.handleToggle(e)}
className={isExpanded ? "active" : "dummy-class"}
>
<p className="mb-0">
<strong>Second</strong>
</p>
</div>
</div>
</div>
</div>
);
}
}
export default PageContentSupportFaq;
Every element must have its seperate expanded value. So we need an array in state.
And here is the code:
import React, { Component } from "react";
class PageContentSupportFaq extends Component {
state = {
items: [
{ id: 1, name: "First", expanded: false },
{ id: 2, name: "Second", expanded: true },
{ id: 3, name: "Third", expanded: false }
]
};
handleToggle = id => {
const updatedItems = this.state.items.map(item => {
if (item.id === id) {
return {
...item,
expanded: !item.expanded
};
} else {
return item;
}
});
this.setState({
items: updatedItems
});
};
render() {
return this.state.items.map(el => (
<div
key={el.id}
onClick={() => this.handleToggle(el.id)}
className={el.expanded ? "active" : "dummy-class"}
>
<p className="mb-0">
<strong>{el.name}</strong>
<span> {el.expanded.toString()}</span>
</p>
</div>
));
}
}
export default PageContentSupportFaq;
You can get two state one state for first and another for a second and handle using two function like this
import React, { Component } from 'react';
class PageContentSupportFaq extends Component {
constructor(props) {
super(props)
this.state = {
isExpanded: false,
isExpanded2:false,
}
}
handleToggle(e){
this.setState({
isExpanded: !this.state.isExpanded
})
}
handleToggle2(e){
this.setState({
isExpanded2: !this.state.isExpanded2
})
}
render() {
const {isExpanded,isExpanded2} = this.state;
return (
<div className="section__support--faq section__full--gray position-relative">
<div className="container section__faq">
<p className="p--thin text-left">FAQ</p>
<h2 className="section__faq--title overflow-hidden pb-4">Title</h2>
<p className="mb-5">Subtitle</p>
<div className="faq__columns">
<div onClick={(e) => this.handleToggle(e)} className={isExpanded ? "active" : "dummy-class"}>
<p className="mb-0"><strong>First</strong></p>
</div>
<div onClick={(e) => this.handleToggle2(e)} className={isExpanded2 ? "active" : "dummy-class"}>
<p className="mb-0"><strong>Second</strong></p>
</div>
</div>
</div>
</div>
);
}
}
export default PageContentSupportFaq;
You'll need to track toggled classes in array, that way it will support arbitrary number of components:
// Save elements data into array for easier rendering
const elements = [{ id: 1, name: "First" }, { id: 2, name: "Second" }];
class PageContentSupportFaq extends Component {
constructor(props) {
super(props);
this.state = {
expanded: []
};
}
handleToggle(id) {
this.setState(state => {
if (state.isExpanded.includes(id)) {
return state.isExpanded.filter(elId => elId !== id);
}
return [...state.expanded, id];
});
}
render() {
return elements.map(el => (
<div
key={el.id}
onClick={() => this.handleToggle(el.id)}
className={this.isExpanded(el.id) ? "active" : "dummy-class"}
>
<p className="mb-0">
<strong>{el.name}</strong>
</p>
</div>
));
}
}

Getting error while closing the react-modal

here when a user click on a picture of the UserProfile component, a modal opens with details about the picture. But when a user closes the modal, an error is generated.
Error:
Cannot read property 'uid' of undefined
at t.value (PostListItem.js:68)
I think t is trying to rendering postlistItem after modal close which should not happen as the content is set to '' while closing the modal.
//UserProfile
class UserProfile extends React.Component{
constructor(props){
super(props);
this.state = {
isFollowed: false,
content: undefined
}
}
componentDidMount(){
this.props.dispatch(usersFetchData(`http://localhost:5000/api/user/
${this.props.match.params.uid}`));
(Object.keys(this.props.user).length !== 0) &&
(this.props.user.followers.includes(this.props.currentUser.uid)) &&
this.setState({isFollowed: true});
}
componentWillUnmount(){
this.props.dispatch(resetUser());
}
onFollow = () =>{
if(this.state.isFollowed){
this.props.dispatch(removeFollower(this.props.user.uid,
this.props.currentUser.uid));
this.props.dispatch(removeFollowing(this.props.currentUser.uid,
this.props.user.uid));
this.setState({isFollowed: false});
}else{
this.props.dispatch(addFollower(this.props.user.uid, this.props.currentUser.uid));
this.props.dispatch(addFollowing(this.props.currentUser.uid,this.props.user.uid));
this.setState({isFollowed: true});
}
}
openModal = (post) => {
this.setState({content:post});
console.log(this.state);
}
closeModal = () =>{
this.setState(() => ({ content: '' }));
console.log(this.state);
}
render(){
if (this.props.hasErrored) {
return <p>Sorry! There was an error loading the items</p>;
}
if (this.props.isLoading) {
return <p>Loading…</p>;
}
return(
<div className="userProfile">
<div>
{console.log(this.props.user)}
{ Object.keys(this.props.user).length !== 0 &&
<div className="user__details">
<div className="user__dp">
<div className="dp__container">
<img src={this.props.user.avatar} alt=
{this.props.user.name}/>
</div>
</div>
<div className="user__description">
<p className="user__name">
{this.props.user.name}</p>
<div className="user__button">
{(this.props.currentUser.uid ===
this.props.user.uid) ?
<button className="ef__button"><Link
to={`/${this.props.user.uid}/edit`}>Edit Profile</Link></button> :
<button
className="ef__button"
onClick={this.onFollow}>
{this.state.isFollowed? 'Following': 'Follow'}
</button>
}
</div>
</div>
</div>
}
</div>
<div className="user__bio">
<p>{this.props.user.bio}</p>
</div>
<div>
<h3>Posts</h3>
<div className="userContent">
{this.props.user.posts &&
this.props.user.posts.map((post) =>{
return(
<div className="userPost">
<img src={post.content} onClick={() =>
this.openModal(post)}/>
</div>
);
})
}
<ContentModal
content={this.state.content}
closeModal={this.closeModal}
/>
</div>
</div>
</div>
);
}
}
const mapStateToProps = (state) =>{
console.log(state);
return{
currentUser: state.auth,
user: state.users,
hasErrored: state.usersHasErrored,
isLoading: state.usersIsLoading
}
};
export default connect(mapStateToProps)(UserProfile);
//contentModal
const ContentModal = (props) => (
<Modal
isOpen={!!props.content}
onRequestClose={props.closeModal}
shouldCloseOnOverlayClick={true}
shouldCloseOnEsc={true}
contentLabel="content"
closeTimeoutMS={200}
className="content__modal"
>
<div className="post__container">
{<PostListItem {...props.content}/>}
</div>
{console.log(props)}
</Modal>
You get the issue because intially the content is undefined and when you are closing the model the content is set to empty string so uid won't be available so call PostListItem only when content is not undefined and not empty.
Add the below condition in ContentModal component
{typeof props.content != "undefined" && props.content != "" && <PostListItem {...props.content}/>}

Reactjs use function from parent

I have 2 files. One is my app.js and the other one is productmodal.js
app.js gets a productlist from an api call. It views these productst in a list.
When a user clicks on the image productmodal.js is showed.
productmodal.js shows a popup with a bigger image, productname(title) and a button called "Product niet aanwezig" (product unavailable) if the user clicks on this link a mail is send to an other user.
When the button is click I also want to activate an other function (getUpdatedProduct). This function is gonna do a long polling call to a link to check when the product is updated to a new product and update this product in the app.
The problem is: I don't know how to call the function 'getUpdatedProduct' in productmodal.js
I get an error: Uncaught TypeError: Cannot read property 'getUpdatedProduct' of undefined
I tried some of these solutions https://reactjs.org/docs/faq-functions.html. Especially the arrow function in render, because its generating a new function every time when the modal is clicked (which I need).
But nothing seems to work. Has anyone some idea's?
App.js:
import React from 'react';
import image from '../images/sogyologo.svg';
import ProductModal from './ProductModal.js';
class App extends React.Component {
constructor(props) {
super(props);
this.toggleModal = this.toggleModal.bind(this);
this.state = {
isLoading: true,
orders: [],
dealtOrders: [],
productDetail: [],
open: false,
modal: []
}
}
toggleModal(event)
{
console.log(event);
let itemIndex = event.target.getAttribute("data-itemIndex");
console.log(itemIndex);
const productModal = this.state.orders[itemIndex];
console.log(productModal);
this.setState({
open: true,
modal: this.state.orders[itemIndex]
});
}
handleClose() {
this.setState({
open: !this.state.open
});
}
componentWillMount() {
localStorage.getItem('orders') && this.setState({
orders: JSON.parse(localStorage.getItem('orders')),
isLoading: false
})
}
componentDidMount() {
if (!localStorage.getItem('orders')){
this.fetchData();
} else {
console.log('Using data from localstorage');
}
}
fetchData() {
fetch('http://localhost:54408/api/orders/all/testing-9!8-7!6/10-04-2018')
.then(response => response.json())
.then(parsedJSON => parsedJSON.map(product => (
{
productname: `${product.ProductName}`,
image: `${product.Image}`,
quantity: `${product.Quantity}`,
isconfirmed: `${product.IsConfirmed}`,
orderid: `${product.OrderId}`
}
)))
.then(orders => this.setState({
orders,
isLoading: false
}))
.catch(error => console.log('parsing failed', error))
}
// componentWillUpdate(nextProps, nextState) {
// localStorage.setItem('orders', JSON.stringify(nextState.orders));
// localStorage.setItem('ordersDate', Date.now());
// }
render() {
this.handleDoneAction = event =>
{
let itemIndex = event.target.getAttribute("data-itemIndex");
let prevOrders = [...this.state.orders];
let dealtOrders = [...this.state.dealtOrders];
const itemToMoveAtLast = prevOrders.splice(itemIndex, 1);
const addToDealtOrders = dealtOrders.concat(itemToMoveAtLast);
this.setState({dealtOrders: addToDealtOrders});
this.setState({orders: prevOrders});
};
this.handleUndoAction = event =>
{
let itemIndex = event.target.getAttribute("data-itemIndex");
let orders = [...this.state.orders];
let dealtOrders = [...this.state.dealtOrders];
const undoDealtOrder = dealtOrders.splice(itemIndex, 1);
const addToOrders = orders.concat(undoDealtOrder);
this.setState({orders: addToOrders});
this.setState({dealtOrders: dealtOrders});
};
const {isLoading, orders, dealtOrders} = this.state;
return (
<div>
<header>
<img src={image}/>
<h1>Boodschappenlijstje <button className="btn btn-sm btn-danger">Reload</button></h1>
</header>
<div className={`content ${isLoading ? 'is-loading' : ''}`}>
<div className="panel">
{
!isLoading && orders.length > 0 ? orders.map((order, index) => {
const {productname, image, quantity, orderid} = order;
return<div className="product" key={orderid}>
<div className="plaatjediv" onClick={this.toggleModal.bind(this) }>
<img className="img-responsive" data-itemIndex={index} src={image} />
</div>
<div className="productInfo">
<p>{productname}</p>
<p>Aantal: {quantity}</p>
</div>
<div className="bdone">
<button className="btn btn-lg btn-default btndone" data-itemIndex={index} onClick={this.handleDoneAction}>Done</button>
</div>
</div>
}) : null
}
</div>
<h2>Mandje</h2>
<div className="panel">
{
!isLoading && dealtOrders.length > 0 ? dealtOrders.map((dorder, index) => {
const {productname, image, quantity} = dorder;
return<div className="productDone" key={index}>
<div className="plaatjediv">
<img className="img-responsive" src={image} />
</div>
<div className="productInfo">
<p>{productname}</p>
<p>Aantal: {quantity}</p>
</div>
<div className="bdone">
<button className="btn btn-lg btn-default btndone" data-itemIndex={index} onClick={this.handleUndoAction}>Undo</button>
</div>
</div>
}) : null
}
</div>
<ProductModal open={this.state.open} handleClose={this.handleClose.bind(this)}
title={this.state.modal.productname} plaatje={this.state.modal.image} orderid={this.state.modal.orderid}/>
<div className="loader">
<div className="icon"></div>
</div>
</div>
</div>
);
}
}
export default App;
productmodal.js
import React from 'react';
class ProductModal extends React.Component {
constructor() {
super();
this.getUpdatedProduct = this.getUpdatedProduct.bind(this);
}
handleClose() {
this.props.handleClose();
}
UserAction(event) {
let orderid = event.target.value;
fetch('http://localhost:54408/api/orders/change/testing-9!8-7!6/' + orderid + '/10-04-2018');
console.log("order id = " + event.target.value);
this.getUpdatedProduct();
}
getUpdatedProduct() {
console.log("fetching new product");
}
render() {
//const open = this.props.open;
const {title, plaatje, open, orderid} = this.props;
return (
<div className={'modal fade in '+(open?'show':'')} role="dialog">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<button type="button" onClick={this.handleClose.bind(this)} className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 className="modal-title">{title}</h4>
</div>
<div className="modal-body">
<img className="plaatjediv img-responsive" src={plaatje} />
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default"
onClick={this.handleClose.bind(this)}>Sluiten
</button>
<button type="button" onClick={this.UserAction.bind()} value={orderid} className="btn btn-primary">Product niet aanwezig</button>
</div>
</div>
</div>
</div>
)
}
}
export default ProductModal;

React: change order list when button clicked

I am making my first app with Javascript and React and started with a page which views a shopping list. It gets the items from an api call.
If the user clicks on the button 'done' (or should I use an checkbox?) This product should go to the bottom of the list (and be grayed out with css but thats not the problem).
The problem is, I have no clue how to do this. Can anyone help me out a bit?
This is my code:
import React from 'react';
//import image from '../images/header.png';
//import Collapsible from './Collapsible';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
orders: []
}
}
componentWillMount() {
localStorage.getItem('orders') && this.setState({
orders: JSON.parse(localStorage.getItem('orders')),
isLoading: false
})
}
componentDidMount() {
if (!localStorage.getItem('orders')){
this.fetchData();
} else {
console.log('Using data from localstorage');
}
}
fetchData() {
fetch('http://localhost:54408/api/orders/all/15-03-2018')
.then(response => response.json())
.then(parsedJSON => parsedJSON.map(product => (
{
productname: `${product.ProductName}`,
image: `${product.Image}`,
quantity: `${product.Quantity}`,
isconfirmed: `${product.IsConfirmed}`,
orderid: `${product.OrderId}`
}
)))
.then(orders => this.setState({
orders,
isLoading: false
}))
.catch(error => console.log('parsing failed', error))
}
componentWillUpdate(nextProps, nextState) {
localStorage.setItem('orders', JSON.stringify(nextState.orders));
localStorage.setItem('ordersDate', Date.now());
}
render() {
const {isLoading, orders} = this.state;
return (
<div>
<header>
<img src="/images/header.jpg"/>
<h1>Boodschappenlijstje <button className="btn btn-sm btn-danger">Reload</button></h1>
</header>
<div className={`content ${isLoading ? 'is-loading' : ''}`}>
<div className="panel">
{
!isLoading && orders.length > 0 ? orders.map(order => {
const {productname, image, quantity, orderid} = order;
return<div className="product" key={orderid}>
<div className="plaatjediv">
<img className="plaatje" src={image} />
</div>
<div className="productInfo">
<p>{productname}</p>
<p>Aantal: {quantity}</p>
<p>ID: {orderid}</p>
</div>
<div className="bdone">
<button className="btn btn-sm btn-default btndone">Done</button>
</div>
</div>
}) : null
}
</div>
<div className="loader">
<div className="icon"></div>
</div>
</div>
</div>
);
}
}
export default App;
You can achieve by using this :
this.handleDoneAction = event = > {
let itemIndex = event.target.getAttribute("data-itemIndex");
let prevOrders = [...this.state.orders];
var itemToMoveAtLast = prevOrders.splice(itemIndex, 1);
var updatedOrderList = prevOrders.concat(itemToMoveAtLast);
this.setState({order: updatedOrderList})
}
I have attach an event handler on the button handleDoneAction.
<button className="btn btn-sm btn-default btndone" data-itemIndex={index} onClick={this.handleDoneAction}>Done</button>
the attribute data-itemIndex is the index of the object in orders array.
And your map function will be like this:
orders.map((order, index) => {
//content
})
ANd for the different style effects on the done products, I will suggest you to use different array for all done products.

Resources