Cannot read property 'map' of undefined in React Redux? - javascript

we are currently developing an e-commerce website using react-redux as front-end. It's working fine while passing the local json data using json-server for mock test but while real api url is passed then occur this TypeError: Cannot read property 'map' of undefined error. Please any one support me to solve this problem.
right-sidebar.jsx:
import React, { Component } from "react";
import Slider from "react-slick";
import "../common/index.scss";
import { connect } from "react-redux";
// import custom Components
import Service from "./common/service";
import BrandBlock from "./common/brand-block";
import NewProduct from "../common/new-product";
import Breadcrumb from "../common/breadcrumb";
import DetailsWithPrice from "./common/product/details-price";
import DetailsTopTabs from "./common/details-top-tabs";
import { addToCart, addToCartUnsafe, addToWishlist } from "../../actions";
import ImageZoom from "./common/product/image-zoom";
import SmallImages from "./common/product/small-image";
class RightSideBar extends Component {
constructor() {
super();
this.state = {
nav1: null,
nav2: null,
};
}
componentDidMount() {
this.setState({
nav1: this.slider1,
nav2: this.slider2,
});
}
render() {
const {
symbol,
item,
addToCart,
addToCartUnsafe,
addToWishlist,
} = this.props;
console.log(item);
var products = {
slidesToShow: 1,
slidesToScroll: 1,
dots: false,
arrows: true,
fade: true,
};
var productsnav = {
slidesToShow: 3,
swipeToSlide: true,
arrows: false,
dots: false,
focusOnSelect: true,
};
return (
<div>
{/* <Breadcrumb title={" Product / " + item.name} /> */}
{/*Section Start*/}
{item ? (
<section className="section-b-space">
<div className="collection-wrapper">
<div className="container">
<div className="row">
<div className="col-lg-9 col-sm-12 col-xs-12">
<div className="container-fluid">
<div className="row">
<div className="col-xl-12">
<div className="filter-main-btn mb-2">
<span className="filter-btn">
<i
className="fa fa-filter"
aria-hidden="true"
></i>{" "}
filter
</span>
</div>
</div>
</div>
<div className="row">
<div className="col-lg-6 product-thumbnail">
<Slider
{...products}
asNavFor={this.state.nav2}
ref={(slider) => (this.slider1 = slider)}
className="product-slick"
>
{item.variants.map((vari, index) => (
<div key={index}>
<ImageZoom
image={vari.images}
className="img-fluid image_zoom_cls-0"
/>
</div>
))}
</Slider>
<SmallImages
item={item}
settings={productsnav}
navOne={this.state.nav1}
/>
</div>
<DetailsWithPrice
symbol={symbol}
item={item}
navOne={this.state.nav1}
addToCartClicked={addToCart}
BuynowClicked={addToCartUnsafe}
addToWishlistClicked={addToWishlist}
/>
</div>
</div>
<DetailsTopTabs item={item} />
</div>
<div className="col-sm-3 collection-filter">
{/* <BrandBlock/> */}
<Service />
{/*side-bar single product slider start*/}
<NewProduct />
{/*side-bar single product slider end*/}
</div>
</div>
</div>
</div>
</section>
) : (
""
)}
{/*Section End*/}
</div>
);
}
}
const mapStateToProps = (state, ownProps) => {
let productId = ownProps.match.params.id;
return {
item: state.data.products.find((el) => el.id == productId),
symbol: state.data.symbol,
};
};
export default connect(mapStateToProps, {
addToCart,
addToCartUnsafe,
addToWishlist,
})(RightSideBar);
shop.js:
/**
* Mocking client-server processing
*/
import axios from "axios";
// import _products from './data.json'
import React, { useState, useEffect } from "react";
import store from "../store";
import { receiveProducts } from "../actions/index";
const TIMEOUT = 100;
const _products = axios
.get(`http://eversoftgroup.ddns.net:8000/apps/product/`)
.then((response) => {
return response.data;
});
const _category = axios
.get(`http://localhost:4000/categories`)
.then((response) => {
return response.data;
});
export default {
getProducts: (cb, timeout) =>
setTimeout(() => cb(_products), timeout || TIMEOUT),
getCategories: (cb, timeout) =>
setTimeout(() => cb(_category), timeout || TIMEOUT),
buyProducts: (payload, cb, timeout) =>
setTimeout(() => cb(), timeout || TIMEOUT),
};

Related

ReactJS, Swiper slider with axios

I have a Swiper slider on a react website, when I take the data from a local json file everything works fine. I had to take the data from public foler so I used axios but I can't scroll anymore in the slider. I think it's a conflict between the Axios and the Swiper plugin but I have no idea how to solve it.
Thanks! :)
Here is the code from the page:
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import Loader from "../container/Loader";
import { Helmet } from "react-helmet";
import { Col } from "react-bootstrap";
import Cookies from "../components/cookies";
import LayoutDefault from "../container/LayoutDefault";
import HeaderProject from "../components/header/HeaderProject";
import ImageSlider from "../container/ImageSlider";
const ProjectPage = ({ match }) => {
const { params: { projectId } } = match;
const [projects, setProjects] = useState(null)
useEffect(() => {
var isCancelled = false;
axios.get("./projects.json").then(
(response) => !isCancelled ? setProjects(response.data) : console.log("is canceled")
).catch(
(err) => console.log(err)
)
}, [])
const goToPreviousPage = () => {
if (window.history.length === 1) {
window.location = "/"
} else {
window.history.back();
}
}
return (
<Loader>
<Helmet>
<title>TheBrandBar | {projects ? projects[projectId - 1].title : ""}</title>
</Helmet>
<Cookies />
<LayoutDefault className="template-color-2 bg_color--4 project-page">
<button onClick={goToPreviousPage} className="page-close" />
<Col>
<HeaderProject
title={projects ? projects[projectId - 1].title : ""}
description={projects ? projects[projectId - 1].description : ""}
/>
</Col>
<ImageSlider
index={projectId}
projects = {projects}
/>
</LayoutDefault>
</Loader>
);
};
export default ProjectPage;
and imageSlider component
import React, { useState } from 'react';
import { Col } from "react-bootstrap";
import SliderSwiper from "../components/swiper";
const ImageSlider = ({ index, projects }) => {
const [swiper, updateSwiper] = useState(null);
const settings = {
slidesPerView: "auto",
spaceBetween: 0,
autoplay: false,
mousewheel: true,
loop: false,
freeMode: true,
};
const goNext = () => {
if (swiper !== null) {
swiper.slideNext();
}
};
// const goPrev = () => {
// if (swiper !== null) {
// swiper.slidePrev();
// }
// };
return (
<div className="pt--10 pb-10">
<SliderSwiper
reference={updateSwiper}
settings={settings}
>
{
projects ? projects[index - 1].images.map((image) => (
<div key={image} className="image-slide mt--15">
<img src={`${process.env.PUBLIC_URL}/projects/${index}/${image}`} alt="" />
</div>
)) : ""
}
</SliderSwiper>
{/* <button onClick={goPrev} className="swipper-btn swiper-btn-prev">
<i className="fa fa-angle-left" />
</button> */}
<Col>
<div onClick={goNext} className="scroll-btn mt--25">
<span>SCROLL TO SEE MORE</span>
<span className="btn-arrow" />
</div>
</Col>
</div>
);
};
export default ImageSlider;

Cart Array in useState won't update with onClick Event

I just began learning React and learning how to use Context Api. I am trying to update my cart when user clicks the add to cart button from the product page but for some reason it won't update the state.
Here is my code:
context api:
import React, { createContext, useEffect, useState } from 'react';
import { detailProduct, storeProducts } from './data';
const ProductContext = createContext();
const ProviderContext = ({ children }) => {
const [products, setProducts] = useState({
product: [],
detailsProduct: detailProduct,
cart: [],
modalOpen: false,
modalProduct: detailProduct,
});
const { product, detailsProduct, cart, modalOpen, modalProduct } = products;
const newProducts = () => {
let tempProducts = [];
storeProducts.forEach((item) => {
const singleItem = { ...item };
tempProducts = [...tempProducts, singleItem];
});
setProducts({
...products,
product: tempProducts,
});
};
useEffect(() => {
newProducts();
}, []);
const getItem = (id) => {
const singleProduct = product.find((item) => item.id === id);
return singleProduct;
};
const handleDetail = (id) => {
const newProduct = getItem(id);
setProducts({ ...products, detailsProduct: newProduct });
};
const addToCart = (id) => {
let tempProducts = [...product];
const index = tempProducts.indexOf(getItem(id));
const cartProduct = tempProducts[index];
cartProduct.inCart = true;
cartProduct.count = 1;
const price = cartProduct.price;
cartProduct.total = price;
setProducts({
...products,
product: tempProducts,
cart: [...cart, cartProduct],
});
console.log(products);
};
const openModal = (id) => {
const product = getItem(id);
setProducts({ ...products, modalProduct: product, modalOpen: true });
console.log(products);
};
const closeModal = () => {
setProducts({ ...products, modalOpen: false });
};
return (
<ProductContext.Provider
value={{
...products,
handleDetail: handleDetail,
addToCart: addToCart,
openModal: openModal,
closeModal: closeModal,
}}
>
{children}
</ProductContext.Provider>
);
};
const ConsumerContext = ProductContext.Consumer;
export { ProviderContext, ConsumerContext };
My product page:
import React, { Fragment } from 'react';
import styled from 'styled-components';
import { Link } from 'react-router-dom';
import { ConsumerContext } from '../Context';
import PropTypes from 'prop-types';
const Product = ({ product }) => {
const { id, title, img, price, inCart } = product;
return (
<ProductWrapper className='col-9 mx-auto col-md-6 col-lg-3 my-3'>
<div className='card'>
<ConsumerContext>
{(value) => (
<div
className='img-container p-5'
onClick={() => value.handleDetail(id)}
>
<Link to='/details'>
<img src={img} alt='product' className='card-img-top' />
</Link>
<button
className='cart-btn'
disabled={inCart ? true : false}
onClick={() => {
value.addToCart(id);
value.openModal(id);
}}
>
{inCart ? (
<p className='text-capitalize mb-0' disabled>
in cart
</p>
) : (
<i className='fas fa-cart-plus'></i>
)}
</button>
</div>
)}
</ConsumerContext>
<div className='card-footer d-flex justify-content-between'>
<p className='align-self-center mb-0'>{title}</p>
<h5 className='tex-blue font-italic mb-0'>
<span className='mr-1'>$</span>
{price}
</h5>
</div>
</div>
</ProductWrapper>
);
};
export default Product;
I am also using the onClick element on the product details page which for some reason works while the one on the product page doesn't work. here is the product details code:
import React from 'react';
import { ConsumerContext } from '../Context';
import { Link } from 'react-router-dom';
import { ButtonContainer } from './Button';
const ProductDetails = () => {
return (
<ConsumerContext>
{(value) => {
const { id, company, img, info, price, title, inCart } =
value.detailsProduct;
return (
<div className='container py-5'>
{/* {title} */}
<div className='row'>
<div className='col-10 mx-auto text-center text-slanted text-blue my-5'>
<h1>{title}</h1>
</div>
</div>
{/* {title} */}
{/* {product info} */}
<div className='row'>
<div className='col-10 mx-auto col-md-6 my3'>
<img src={img} alt='product' className='img-fluid' />
</div>
{/* {product text} */}
<div className='col-10 mx-auto col-md-6 my3 text-capitalize'>
<h2>model : {title}</h2>
<h4 className='text-title text-uppercase text-muted mt-3 mb-2'>
made by : <span className='text-uppercase'>{company}</span>
</h4>
<h4 className='text-blue'>
<strong>
price : <span>$</span>
{price}
</strong>
</h4>
<p className='text-capitalize font-weight-bold mt-3 mb-0'>
about product:
</p>
<p className='text-muted lead'>{info}</p>
{/* {buttons} */}
<div>
<Link to='/'>
<ButtonContainer>back to products</ButtonContainer>
</Link>
<ButtonContainer
cartButton
disabled={inCart ? true : false}
onClick={() => {
value.addToCart(id);
// value.openModal(id);
}}
>
{inCart ? 'in cart' : 'add to cart'}
</ButtonContainer>
</div>
</div>
</div>
</div>
);
}}
</ConsumerContext>
);
};
export default ProductDetails;

How to make React App to filter only one item

Following a course by Andrei Neagoie on Udemy, I'm making this robots app that displays and filters data gotten from an API. I've customized it a little bit and added a carousel feature, but now, when I hit the searchbox and try to filter it displays more than one item. I want it displaying only one item, how can I do this?
This is the problem I'm having: https://imgur.com/fsgesBs
App.js
import React, { Component } from 'react'
//import CardList from './components/CardList';
import SearchBox from './components/SearchBox';
import Splider from './components/Splider';
class App extends Component {
constructor(){
super()
this.state = {
robots: [],
searchField: ''
}
}
componentDidMount(){
fetch('https://jsonplaceholder.typicode.com/users')
.then(res => {
return res.json();
})
.then(users => {
this.setState({
robots: users
});
});
}
onSearchChange = (e) => {
this.setState({
searchField: e.target.value
});
}
render() {
const filtered = this.state.robots.filter(robot => {
return robot.name.toLowerCase().includes(this.state.searchField.toLowerCase());
});
// Main Render
return (
<div className="App tc">
<h1>RoboBros!</h1>
<SearchBox searchChange={this.onSearchChange}/>
<Splider robots={filtered}/>
{/* <CardList robots={filtered}/> */}
</div>
)
}
}
export default App
SearchBox.js
import React from 'react'
import '../index.css'
const SearchBox = ({ searchChange, searchField }) => {
return (
<div className="search-div">
<input className="search-box center" type="search" placeholder="Search Robots" onChange={searchChange}/>
<button className="search-btn">Search</button>
</div>
)
}
export default SearchBox;
Cards.js(Individual card items)
import React from 'react'
import '../styles/Cards.css';
const Cards = ({ name, id, email }) => {
return (
<div className="cards-wrapper dib br3 pa3 ma2 grow pointer">
<img className="cent" src={`https://robohash.org/${id}?set=set3`} alt="robots"/>
<div className="text">
<h3>{name}</h3>
<h4>{email}</h4>
</div>
</div>
)
}
export default Cards;
CardList.js
import React from 'react';
import Cards from './Cards';
const CardList = ({robots}) => {
const cardComponent = robots.map((robot, i) => {
return <Cards key={i} id={robots[i].id} name={robots[i].name} email={robots[i].email}/>;
})
return(
<div>
{cardComponent}
</div>
);
}
export default CardList;
Splider.js(Component that holds the Carousel/Slider library)
import React from 'react';
import { Splide, SplideSlide } from '#splidejs/react-splide';
import '#splidejs/splide/dist/css/themes/splide-sea-green.min.css';
import '../styles/Cards.css';
const Splider = ({robots}) => {
const cardSplide = robots.map((robot, i) => {
return (
<SplideSlide key={i} className="cards-wrapper dib br3 pa3 ma2">
<img src={`https://robohash.org/${robots[i].id}?set=set3`} alt="robots"/>
<h3>{robot.name}</h3>
<h4>{robot.email}</h4>
</SplideSlide>
);
});
return(
<Splide options={{
rewind: true,
width: '100%',
gap: '1rem',
perPage: 3,
perMove: 1,
focus: 'center',
type: 'loop',
easing: 'ease',
}}>
{cardSplide}
</Splide>
);
}
export default Splider;
The issue is with type: loop option:
import React from "react";
import { Splide, SplideSlide } from "#splidejs/react-splide";
import "#splidejs/splide/dist/css/themes/splide-sea-green.min.css";
import "../styles/Cards.css";
const Splider = ({ robots }) => {
return (
<Splide
options={{
rewind: true,
width: "100%",
gap: "1rem",
perPage: 3,
perMove: 1,
focus: "center",
//type: "loop",
easing: "ease"
}}
>
{robots.map((robot, i) => {
return (
<SplideSlide key={robot.id} className="cards-wrapper dib br3 pa3 ma2">
<img
src={`https://robohash.org/${robot.id}?set=set3`}
alt="robots"
/>
<h3>{robot.name}</h3>
<h4>{robot.email}</h4>
</SplideSlide>
);
})}
</Splide>
);
};
export default Splider;
This is the issue in splidejs project: https://github.com/Splidejs/splide/issues/145
It shows as fixed, so probably you need to wait for react-splide to include the fix as well in it's latest version.

ReactJS: TypeError: render is not a function updateContextConsumer

I'm trying to learn the Context API, and what I want to achieve, is showing the button Login and Sign up on the navigation but I had another error that had from another post I read the docs but me reading and not doing visually that how I learned by doing it making mistaking.
The buttons should open up two modal windows one login and sign up form.
Modal.js
import React from 'react';
import ReactDOM from "react-dom";
import Modal from "react-modal";
import ModalContext from '../Forms/ModalContext';
class ModalProvider extends React.Component {
state = {
loginOpened: false,
signupOpened: false
};
openModal = modalType => () => {
if (modalType === "login") {
this.setState({
loginOpened: true,
signupOpened: false
});
} else if (modalType === "signup") {
this.setState({
loginOpened: false,
signupOpened: true
});
}
};
closeModal = modalType => () => {
if (modalType === "login") {
this.setState({
loginOpened: false
});
} else if (modalType === "signup") {
this.setState({
signupOpened: false
});
}
};
render(props) {
return (
<ModalContext.Provider value={{openModal: this.openModal, closeModal: this.closeModal}}>
<Modal isOpen={loginOpened} onRequestClose={this.closeModal("login")}>
<h1>Login</h1>
<button onClick={this.openModal("signup")}>Open Signup</button>
<button onClick={this.closeModal("login")}>Close this modal</button>
</Modal>
<Modal isOpen={signupOpened} onRequestClose={this.closeModal("signup")}>
<h1>Sign Up</h1>
<button onClick={this.openModal("login")}>Open Login</button>
<button onClick={this.closeModal("signup")}>Close this modal</button>
</Modal>
{props.children}
</ModalContext.Provider>
)
}
}
export default ModalProvider
ModalContext.js
I don't know why the person that helped me and explain did a very great job explain to but just want to know why it is just this line of code.
import {createContext} from 'react'
export default createContext()
Navigation.js
import React from 'react';
import { BrowserRouter as Router, Link } from 'react-router-dom';
import Dropdown from "../dropdowns/dropdowns";
import hamburger from "../images/menu.svg"
// This will display the login and sign up buttons
import ModalContext from '../Forms/ModalContext';
class Navigation extends React.Component {
constructor(props) {
super(props);
this.state = {
isExpanded: false
};
}
handleToggle(e) {
e.preventDefault();
this.setState(prevState => ({
isExpanded: !prevState.isExpanded, // negate the previous expanded state
}));
}
render(props) {
const { isExpanded } = this.state;
return (
<Router>
<div className="NavbarContainer main">
<div className="mobilecontainer LeftNav">
<h2 className="BrandName LeftNav mobileboxmenu inline FarRight">Kommonplaces</h2>
<div className="hamburger inlinev" >
<img
onClick={e => this.handleToggle(e)}
alt="menubtn"
src={hamburger}
/>
</div>
</div>
<div className={`NavBar collapsed ${isExpanded ? "is-expanded" : ""}`}>
<div className="col-a">
<Dropdown/>
<li className="RightNav"><Link to="/">Host Your Space</Link></li>
<li className="RightNav"><Link to="/">About Us</Link></li>
<li className="RightNav"><Link to="/">Contact Us</Link></li>
</div>
<div className="col-c">
{ /* 4. call the prop functions in `Navigation` component */ }
<ModalContext.Consumer>
{({openModal, closeModal}) => <button onClick={openModal("login")}>Login</button>}
{({openModal, closeModal}) => <button onClick={openModal('signup')}>Sign Up</button>}
</ModalContext.Consumer>
</div>
</div>
</div>
</Router>
);
}
}
export default Navigation;
So you first created the ModalContext and the context gives you a Provider and a Consumer.
If you want to use the context for a Consumer, there should be a Provider providing it. For that to happen, the Consumer should be a child of the Provider so that it has access to it.
<Provider>
....
...
<Consumer />
...
</Provider>
But in your case, Provider is not a ancestor of the Consumer.
Typically this is how this gets played out.
Navigation.js
import React from "react";
import { BrowserRouter as Router, Link } from "react-router-dom";
import Dropdown from "../dropdowns/dropdowns";
import hamburger from "../images/menu.svg";
// This will display the login and sign up buttons
import ModalContext from "../Forms/ModalContext";
import ModalProvider from "../Forms/ModalProvider";
class Navigation extends React.Component {
constructor(props) {
super(props);
this.state = {
isExpanded: false
};
}
handleToggle(e) {
e.preventDefault();
this.setState(prevState => ({
isExpanded: !prevState.isExpanded // negate the previous expanded state
}));
}
render(props) {
const { isExpanded } = this.state;
return (
<Router>
{/* Modal provider provides the context to all the children */}
<ModalProvider>
<div className="NavbarContainer main">
<div className="mobilecontainer LeftNav">
<h2 className="BrandName LeftNav mobileboxmenu inline FarRight">
Kommonplaces
</h2>
<div className="hamburger inlinev">
<img
onClick={e => this.handleToggle(e)}
alt="menubtn"
src={hamburger}
/>
</div>
</div>
<div
className={`NavBar collapsed ${isExpanded ? "is-expanded" : ""}`}
>
<div className="col-a">
<Dropdown />
<li className="RightNav">
<Link to="/">Host Your Space</Link>
</li>
<li className="RightNav">
<Link to="/">About Us</Link>
</li>
<li className="RightNav">
<Link to="/">Contact Us</Link>
</li>
</div>
<div className="col-c">
{/* 4. call the prop functions in `Navigation` component */}
{/* Consumer has access to context as children as function*/}
<ModalContext.Consumer>
{({openModal, closeModal, loginOpened, signupOpened}) => {
return (
<React.Fragment>
<button onClick={openModal("login")}> Login</button>
<button onClick={openModal("signup")}>Sign Up</button>
<Modal
isOpen={loginOpened}
onRequestClose={closeModal("login")}
>
<h1>Login</h1>
<button onClick={openModal("signup")}>
Open Signup
</button>
<button onClick={closeModal("login")}>
Close this modal
</button>
</Modal>
<Modal
isOpen={signupOpened}
onRequestClose={closeModal("signup")}
>
<h1>Sign Up</h1>
<button onClick={openModal("login")}>
Open Login
</button>
<button onClick={closeModal("signup")}>
Close this modal
</button>
</Modal>
</React.Fragment>
);
}}
</ModalContext.Consumer>
</div>
</div>
</div>
</ModalProvider>
</Router>
);
}
}
export default Navigation;
ModalProvider.js
import React from "react";
import ReactDOM from "react-dom";
import Modal from "react-modal";
import ModalContext from "../Forms/ModalContext";
class ModalProvider extends React.Component {
state = {
loginOpened: false,
signupOpened: false
};
openModal = modalType => () => {
if (modalType === "login") {
this.setState({
loginOpened: true,
signupOpened: false
});
} else if (modalType === "signup") {
this.setState({
loginOpened: false,
signupOpened: true
});
}
};
closeModal = modalType => () => {
if (modalType === "login") {
this.setState({
loginOpened: false
});
} else if (modalType === "signup") {
this.setState({
signupOpened: false
});
}
};
render(props) {
return (
<ModalContext.Provider
value={{
openModal: this.openModal,
closeModal: this.closeModal,
signupOpened: this.state.signupOpened,
loginOpened: this.state.loginOpened,
}}
>
{props.children}
</ModalContext.Provider>
);
}
}
export default ModalProvider;
I was writing an example app as well so will post it as an answer:
function ToggleModal({ checked, onChange, modalId }) {
console.log('rendering:', modalId);
return (
<label>
{modalId}
<input
type="checkbox"
checked={checked}
onChange={onChange}
/>
</label>
);
}
const ToggleModalContainer = ({ modalId }) => {
const { modals, changeModal } = React.useContext(State);
const checked = modals[modalId];
return React.useMemo(
() =>
ToggleModal({
checked,
modalId,
onChange: () => changeModal(modalId, !checked),
}),
[changeModal, checked, modalId]
);
};
function Modals() {
const state = React.useContext(State);
return Object.entries(state.modals).map(
([key, value]) =>
value && <div key={key}>this is modal {key}</div>
);
}
const State = React.createContext();
const App = () => {
const [modals, setModals] = React.useState({
a: false,
b: false,
c: false,
});
const changeModal = React.useCallback(
(modalId, open) =>
setModals(modals => ({ ...modals, [modalId]: open })),
[]
);
const state = React.useMemo(
() => ({
modals,
changeModal,
}),
[changeModal, modals]
);
return (
<State.Provider value={state}>
<React.Fragment>
{Object.keys(modals).map(modalId => (
<ToggleModalContainer
modalId={modalId}
key={modalId}
/>
))}
<Modals />
</React.Fragment>
</State.Provider>
);
};
//render app
ReactDOM.render(
<App />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Errors with passing data between components in ReactJS

I am trying to pass a state array from one component into another, to share and display the data. So the data is from a rest api that gets saved into an array called saved[]. I am trying to pass this into another component to display my saved articles. I have a few issues:
1 - No data is being displayed in the other component
2 - When switching between routes I get this error:
warning: Can't perform a React state update on an unmounted component.
So my code so far is as follows:
newshero.js
import React, { Component } from 'react';
import './news-hero.css';
import Carousel from "react-multi-carousel";
import "react-multi-carousel/lib/styles.css";
const responsive = {
superLargeDesktop: {
breakpoint: { max: 4000, min: 3000 },
items: 1,
},
desktop: {
breakpoint: { max: 3000, min: 1024 },
items: 1,
},
tablet: {
breakpoint: { max: 1024, min: 464 },
items: 1,
},
mobile: {
breakpoint: { max: 464, min: 0 },
items: 1,
},
};
class NewsHero extends Component {
state = {
loading: false,
data: [],
headline: [],
saved: []
}
saved = headline => {
this.setState(
(prevState) => ({ saved: [...prevState.saved, headline] }),
() => {
console.log('Saved articles = ', this.state.saved);
alert('Article saved');
localStorage.setItem('saved', JSON.stringify(this.state.saved));
localStorage.getItem('saved');
});
}
constructor(props) {
super(props)
this.saved = this.saved.bind(this)
}
onError() {
this.setState({
imageUrl: "../assets/img-error.jpg"
})
}
componentDidMount() {
this.setState({ loading: true, saved: localStorage.getItem('saved') ? JSON.parse(localStorage.getItem('saved')) : [] })
fetch('https://newsapi.org/v2/everything?q=timbaland&domains=rollingstone.com,billboard.com&excludeDomains=townsquare.media&apiKey=8')
.then(headline => headline.json())
.then(headline => this.setState({ headline: headline.articles, loading: false }, () => console.log(headline.articles)))
}
render() {
return (
<div className="hero">
<h2 className="text-left">News</h2>
{this.state.loading
? "loading..."
: <div>
<Carousel
additionalTransfrom={0}
showDots={true}
arrows={true}
autoPlaySpeed={3000}
autoPlay={false}
centerMode={false}
className="carousel-hero"
containerClass="container-with-dots"
dotListClass="dots"
draggable
focusOnSelect={false}
infinite
itemClass="carousel-top"
keyBoardControl
minimumTouchDrag={80}
renderButtonGroupOutside={false}
renderDotsOutside
responsive={responsive}>
{this.state.headline.map((post, indx) => {
return (
<div className="text-left mt-5" key={indx}>
<img className="media-img card-img-top card-img-hero" src={post.urlToImage} alt="Alt text"></img>
<div className="card-body container hero-text-body">
<h1 className="card-title hero-title text-truncate">{post.title}</h1>
<button className="btn-primary btn mt-2 mb-4" onClick={() => this.saved(post)}>Add this article</button>
<p className="card-text">{post.description}</p>
Read More
</div>
</div>
)
})}
</Carousel>
</div>
}
</div>
)
}
}
export default NewsHero;
main-news.js
import React, { Component } from 'react';
import '../news-main/news-main.css';
import News from '../news/news';
import NewsHero from '../news-hero/news-hero';
import Sports from '../sports/sports';
class NewsMain extends Component {
render() {
return (
<div>
<NewsHero />
<News />
<Sports />
</div>
)
}
}
export default NewsMain;
app.js
import React, { Component } from 'react';
// import logo from './logo.svg';
import './App.css';
import Header from './header/header';
import NewsMain from './news-main/news-main';
import Footer from './footer/footer';
import Home from './home/home';
import { Router } from '#reach/router';
class App extends Component {
constructor(props) {
super(props);
this.state = {saved: []};
}
render() {
return (
<div className="App">
<Header />
<div>
<Router>
<Home default path='/news' savedArticles={this.state.saved} />
<NewsMain path='/news' />
</Router>
</div>
<Footer title="Footer" />
</div>
)
}
}
export default App;
Trying to pass data into the below:
import React, { Component } from 'react';
import '../home/home.css';
class Home extends Component {
componentDidMount() {
this.setState({ loading: true, saved: localStorage.getItem('saved') ? JSON.parse(localStorage.getItem('saved')) : [] })
fetch('https://newsapi.org/v2/everything?q=timbaland&domains=rollingstone.com,billboard.com&excludeDomains=townsquare.media&apiKey=8')
.then(headline => headline.json())
.then(headline => this.setState({ headline: headline.articles, loading: false }, () => console.log('Saved articles', headline.articles)))
}
render() {
return (
<div className="mt-5 saved">
{this.props.savedArticles.map((article, indx) => {
return (
<div className="media mb-5" key={indx}>
<img className="media-img sports-thumb mr-3 mb-3 d-none d-sm-block" src={article.urlToImage} alt="Alt text"></img>
<div className="media-body text-left">
<h5 className="mt-0">{article.title}</h5>
<p className="text-left">{article.description}</p>
Read More
</div>
</div>
)
})}
</div>
)
}
}
export default Home;
Something to do with the state but I can't see where and why? Any idea's

Categories