how to pass values from an array into a prop - javascript

so im trying to pass the value price from this array
const [products, setProducts] = useState(
[{
name: "14K bracelet",
id: "1",
description: "Beautfull 14K gold Bracelet",
price: 100.00,
img: braceletImg,
}]
)
into here
<h1 className="price">{products.price}</h1>{/*this is a prop*/}
I call the prop here in cart
function Cart({ products })
full code of the cart component
function Cart({ products }) {
return(
<div className="Body">
{/* {products.map(pr => <h1 className="price">{pr.price}</h1>)} */}
<div className="Cart-wrapper" >
<div className="cart-header">
<h5 className="Product-name cart-text">Product</h5>
<h5 className="quantity-name cart-text">Quantity</h5>
<h5 className="price-name cart-text">Price</h5>
<Button className="btn btn-plus">+</Button>
<Button className="btn btn-minus">-</Button>
<div className="card-cart">
<img className="braceletimg" src={braceletImg} />
<h1 className="card-body-title">Bracelet title</h1>
<h1 className="card-body-title seemore"><Link className="Link" to="/Bracelets">Learn More</Link></h1>
<hr className="cart-hr"></hr>
</div>
<div className="div-price">
{products.map(pr => <h1 key={pr.id} className="price">{pr.price}</h1>)}
<small className="shippingprice">$5.00 + shipping</small>
</div>
<Button className="btn btn-cart btn-primary"><Link className="Link" to="/Cart/shipping-buynow">Review Cart</Link></Button>
</div>
</div>
</div>
)
}
export default Cart;
hopefully, this gives you a better context of the component

Because products is an array, you either need to use indexing, or you can process them all using .map().
Using indexing:
<h1 className="price">{products[0].price}</h1>
Using .map():
{products.map(pr => <h1 key={pr.id} className="price">{pr.price}</h1>)}
The addition of key={...} is needed so React can optimize the rendering. If you don't add it then React will show warnings in the console output. If the items already have a unique id or key value, then it's best to use that.
Update:
Your Cart component may be getting activated already before products has been initialized, this would explain the undefined errors.
This is quite normal, and to prevent it from being a problem you can check if products is empty:
function Cart({ products }) {
if (!products)
return "Loading...";
return (
// ...
// ...
// ...
);
}

Related

TypeError: setCart is not a function

The setCart is not working in this following code
I have passed cart,setcart as a prop to this function cart is accessable but setcart is not working.
export default function Cart({ cart, setCart }) {
const deletecart = () => {
console.log("delete");
setCart([]);
};
return (
<div>
<div className="container main">
<h4>Items In Cart</h4>
</div>
<h3>Your Cart Items</h3>
<button onClick={deletecart} className="btn btn-primary">
Delete Cart
</button>
<button>Place Your Order</button>
</div>
);
}
<Cart cart={cart} setcart={setCart}></Cart>
should be
<Cart cart={cart} setCart={setCart}></Cart>
(That's a doh!) By the way, this type of thing would be picked up by TypeScript, and is why most React devs use it instead of raw JS.

Having trouble rendering an array of images from an api (Django Rest Framework) response in React

Hi this is my first project in both React and Django Rest Framework and I need to figure this out to complete the project.
The issue I'm having (I believe it's a React one) is that my api is returning an json response which React receives using axios which works fine since when I do the console log all the data is there and Im also able to pass the data to a tag, etc. I would like to display the photos that are being sent to by the api. The link is not the problem as I am able to view the photo in the browser using the link provided by the api. The problem is that I have multiple images in the api response that are set up as an array.
As shown here:
postmanResponse
Response using console:
enter image description here
I guess essentially what I'm asking is there a way that I can make an array/object with the image array that my api is delivering so that I can then use it to show the picture in React?
Any help will be helpful. Thank you!
Here is my code for the React side:
// Import Files
import React, { Component } from 'react';
// Import Axios
import axios from "axios";
// Import Is Mobile
import { isMobile } from 'react-device-detect';
// Import Css
import "./projectDetail.css";
// Mobile Css
import "./projectDetailM.css"
// Lightbox
import { SRLWrapper } from "simple-react-lightbox";
// Import Footer
import Footer from "../Footer/footer"
// Project Detail Class
class ProjectDetail extends Component {
// States
state = {
data: [],
photoIndex: 0,
isOpen: false,
}
// Mount Data to the State
componentDidMount() {
this.handleFetchItem();
}
// Get the project via axios
handleFetchItem = () => {
// Variables
const {
match: { params }
} = this.props
// Set State
this.setState({ loading: true });
// Axios Setup
axios.get('http://127.0.0.1:8000/projects/' + params.ID)
.then(res => {
this.setState({ data: res.data, loading: false });
})
.catch(console.error());
}
// Render the page
render() {
// Const
const { data } = this.state;
const project = data;
// Print to console (Debugging)
//console.log(data);
// Return Page
return (
<div className="projectDetailMainContainer">
<div className="projectDetailGrid">
<div className="projectDetailArea">
<div className="projectNameArea">
<h1 className="projectNameStyling">
{project.title}
</h1>
</div>
<div className="projectAddress1Area">
<h2 className="projectAddress1Styling">
{project.address},
</h2>
</div>
<div className="projectAddress2Area">
<h2 className="projectAddress2Styling">
{project.address2}
</h2>
</div>
<div className="projectCityArea">
<h2 className="projectCityStyling">
{project.city} {project.zipcode}
</h2>
</div>
<div className="projectProgressArea">
<h3 className="projectProgressStyling">
{project.completed}
</h3>
</div>
<div className="projectReturnButton">
<button
className="btnStyleDetailPage"
type="button"
onClick={() => { this.props.history.replace('/projects') }}>
Return to Project List
</button>
</div>
</div>
<div className="projectDetailImageArea">
<SRLWrapper>
<img className="projectImageStyling"
src={require("./placeholders/city.jpg")} alt={project.title} />
</SRLWrapper>
</div>
</div>
<Footer />
</div>
);
}
}
// Export Compoenent
export default ProjectDetail;
You can solve this by implementing a image carousel or iterating over the images array.
First of all you must guarantee that the pictures are properly set on a state (does not matter what type of component). Then, here is one way to show all of the images and solve the problem:
function ImageList(props) {
return (
props.images.map((pic, index) => {
return (
<img key={index} src={pic.src} alt="image" />
);
})
);
}
use map like this
{ data.map(project => { <div className="projectDetailMainContainer">
<div className="projectDetailGrid">
<div className="projectDetailArea">
<div className="projectNameArea">
<h1 className="projectNameStyling">
{project.title}
</h1>
</div>
<div className="projectAddress1Area">
<h2 className="projectAddress1Styling">
{project.address},
</h2>
</div>
<div className="projectAddress2Area">
<h2 className="projectAddress2Styling">
{project.address2}
</h2>
</div>
<div className="projectCityArea">
<h2 className="projectCityStyling">
{project.city} {project.zipcode}
</h2>
</div>
<div className="projectProgressArea">
<h3 className="projectProgressStyling">
{project.completed}
</h3>
</div>
<div className="projectReturnButton">
<button
className="btnStyleDetailPage"
type="button"
onClick={() => { this.props.history.replace('/projects') }}>
Return to Project List
</button>
</div>
</div>
<div className="projectDetailImageArea">
<SRLWrapper>
<img className="projectImageStyling"
src={require("./placeholders/city.jpg")}
alt={project.title} />
</SRLWrapper>
</div>
</div>
<Footer />
</div>
})}
for the images you can access them by index like this
{project.images[0].src}
{project.images[1].src}
{project.images[2].src}
example:
<img src={project.images[0].src} alt="image" />

Can't access nested Objects JSON in React JSX

I can access JSON objects in the results here
useEffect(() => {
fetch(`/user/${userid}`,{
method:'get',
headers:{
"Authorization":`Bearer ${localStorage.getItem('token')}`}
}).then(res=>res.json())
.then(result=>{
console.log(result.user.name) //I can access JSON objects in the results here//
setProfile(result)
})
.catch(err=>console.log(err))
}, [])
I can access JSON while Changing State but it throws errors like UserProfile.user is undefined,UserProfile.posts.length is undefined when rendering JSX. TO access the nested Data I have tried creating more state Variables. It works but the code have become long. I looked for solution in various website but could not find. Any one help me.
return (
<>
{
UserProfile?<div style={{maxWidth:'800px',margin:"0px auto"}}>
<div style={{
display:"flex",
justifyContent:'space-around',
margin:"18px 0px"
}}>
<div>
<img style={{borderBottom:"1px solid grey",width:"160px",height:"160px",borderRadius:"80px"}} src="https://images.unsplash.com/photo-1569466896818-335b1bedfcce?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60"/>
</div>
<div>
<h4>{UserProfile?UserProfile.user.name:"Loading..."}</h4>
<div style={{display:"flex",justifyContent:"space-between",width:"100%"}}>
<h6>{UserProfile.posts.length} posts </h6>
<button onClick={()=>followUser()} className="btn waves-effect waves-light #64b5f6 blue lighten-2" type="button" name="action">Follow</button>
</div>
</div>
</div>
<div className="gallery">
{
UserProfile.posts.map((item)=>{
return(
<img className="item" key={item._id} src={item.photo}/>
)
})
}
</div>
</div>:
<h1>Loading:</h1>
}
</>
)
export default Profile
Based on the code and your inputs, the problem may be because you are trying to access the variables before they are accessible.
As you are making async API call in useEffect() it may take some time before you get data. But, as you are accessing the data before you even get it errors like 'UserProfile.user is undefined', 'UserProfile.posts.length' is undefined will occur'
To avoid such errors make sure you add a check as shown below
<>
{
UserProfile &&
<div style={{maxWidth:'800px',margin:"0px auto"}}>
<div style={{
display:"flex",
justifyContent:'space-around',
margin:"18px 0px"
}}>
<div>
<img style={{borderBottom:"1px solid grey",width:"160px",height:"160px",borderRadius:"80px"}} src="https://images.unsplash.com/photo-1569466896818-335b1bedfcce?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60"/>
</div>
<div>
/* -----> modify it here*/ <h4>{UserProfile ? UserProfile.user && UserProfile.user.name:"Loading..."}</h4>
<div style={{display:"flex",justifyContent:"space-between",width:"100%"}}>
/* -----> modify it here*/ <h6>{UserProfile && UserProfile.posts && UserProfile.posts.length} posts </h6>
<button onClick={()=>followUser()} className="btn waves-effect waves-light #64b5f6 blue lighten-2" type="button" name="action">Follow</button>
</div>
</div>
</div>
<div className="gallery">
{
UserProfile.posts.map((item)=>{
return(
<img className="item" key={item._id} src={item.photo}/>
)
})
}
</div>
</div>
:
<h1>Loading:</h1>
}
</>
I got the solution for this. I got rid of this problem by setting initial state to null. Thank You for answering my query.
//my initial useState declaration//
const [userProfile,setUserProfile]=useState([])
//Solution//
const [userProfile,setUserProfile]=useState(null)
I am new to react so I got into problem.

Passing of Props in ReactJS

Following is my JSX code in a React component which is working fine and currently in use, but in most of React blog posts they are also de structuring an object. My query is - do we have any extra benefit of modifying the code to Version 2 or this is just fine.
First Version (currently in use) -
const CartItems = ({ items }) => items.length ? items.map((x, i) => (
<div key={x.id} className={`cart-item-${i}`}>
<div className="card ">
<div className="cart-item-img">
<img src={x.url} alt={x.altText} className="img" />
</div>
<div className="cart-item-desc">
<h3 className="title">{x.title}</h3>
<p className="text">{x.shortDesc}</p>
</div>
<div className="cart-item-action">
<button className="add">+</button>
<button className="subtract">-</button>
<button className="remove">X</button>
</div>
</div>
</div>)) : []
2nd Version -
const CartItems = ({ items }) => items.length ? items.map((x, i) => {
const {
id,
url,
altText,
title,
shortDesc
} = x;
return (
<div key={id} className={`cart-item-${i}`}>
<div className="card ">
<div className="cart-item-img">
<img src={url} alt={altText} className="img" />
</div>
<div className="cart-item-desc">
<h3 className="title">{title}</h3>
<p className="text">{shortDesc}</p>
</div>
<div className="cart-item-action">
<button className="add">+</button>
<button className="subtract">-</button>
<button className="remove">X</button>
</div>
</div>
</div>)
}) : []
The benefits are mostly aesthetic and subjective, so if you prefer the first one, more power to you and nothing that says you need to change it.
My personal view on the two snippets you posted: I tend to avoid direct returns from arrow functions because I'll oftentimes need to add a log or something else and having to convert back and forth eventually wears on you. This has little to do with the destructuring though, other than destructuring forces you to have a function body and explicit return.

How to properly search in a list in ReactJS

I am trying to set a simple search operation in a user interface as shown below:
I have a total of 70 react-strap cards and each card contain a vessel with name, type and an image. I would like to search the name of the vessel and have the card related to that vessel to pop-up. All my images are currently contained inside the external database Contentful. Below the fields of interests:
The problem is that I don't know how to write a search function that locate a specific value of a list.
Below the code:
SideBar.js
import React from 'react';
import Client from '../Contentful';
import SearchVessel from '../components/SearchVessel';
class Sidebar extends React.Component {
state = {
ships: [],
};
async componentDidMount() {
let response = await Client.getEntries({
content_type: 'cards'
});
const ships = response.items.map((item) => {
const {
name,
slug,
type
} = item.fields;
return {
name,
slug,
type
};
});
this.setState({
ships
});
}
getFilteredShips = () => {
if (!this.props.activeShip) {
return this.state.ships;
}
let targetShip = this.state.ships.filter(
(ship) => this.props.activeShip.name === ship.name
);
let otherShipsArray = this.state.ships.filter((ship) => this.props.activeShip.name !== ship.name);
return targetShip.concat(otherShipsArray);
};
render() {
return (
<div className="map-sidebar">
{this.props.activeShipTypes}
<SearchVessel />
<pre>
{this.getFilteredShips().map((ship) => {
console.log(ship);
return (
<Card className="mb-2">
<CardImg />
<CardBody>
<div className="row">
<img
className="image-sizing-primary"
src={ship.companylogo.fields.file.url}
alt="shipImage"
/>
</div>
<div>
<img
className="image-sizing-secondary"
src={ship.images.fields.file.url}
alt="shipImage"
/>
</div>
<CardTitle>
<h3 className="thick">{ship.name}</h3>
</CardTitle>
<CardSubtitle>{ship.type}</CardSubtitle>
<CardText>
<br />
<h6>Project Details</h6>
<p>For a description of the project view the specification included</p>
</CardText>
<Row style={{ marginTop: '20px' }}>
<div className="buttoncontainer">
<div className="btn btn-cards">
<a
className="buttonLink"
download
href={ship.projectnotes.fields.file.url}
>
Project Notes
</a>
</div>
<div className="btn btn-cards">
<a className="buttonLink" href={ship.abstract.fields.file.url}>
Abstract
</a>
</div>
</div>
</Row>
</CardBody>
</Card>
);
})}
</pre>
</div>
);
}
}
export default Sidebar;
VesselSearch.js
import React, { Component } from 'react';
export default class SearchVessel extends Component {
render() {
const { value, handleSubmit, handleChange } = this.props;
return (
<React.Fragment>
<div className="container">
<div className="row">
<div className="col-10 mx-auto col-md-8 mt-5 text-center">
<h4 className="text-slanted text-capitalize">Search for Vessel</h4>
<form className="mt-4" onSubmit={handleSubmit}>
<label htmlFor="search" className="text-capitalize">
type vessel separated by comma
</label>
<div className="input-group">
<input
type="text"
name="search"
placeholder="Type name of vessel here"
className="form-control"
value={value}
onChange={handleChange}
/>
<div className="input-group-append">
<button type="submit" className="input-group-text bg-primary text-white">
<i className="fas fa-search" />
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</React.Fragment>
);
}
}
What I have done so far:
1) I tried different combination with the filter function and I think I am close. The problem is that when I operate the search nothing happens and in order to find the card of the vessel I want, I have to scroll down until I find it.
I am running out of ideas and if you see something I didn't catch point me in the right direction for solving this issue.
You're close! I would add a field to your state called 'searchText' and then create a method to filter based on that searchText state item.
getFilteredShips = () => this.state.ships.filter(s => s.name.includes(this.state.searchText)
Then just map over those values to render the cards that match the search text. The cards will update each time the searchText value updates.
this.getFilteredShips().map(ship => ..........
React is famous for re-usable component. You will have all the data of these vessels in an array. You will loop through the array and render the items with card component.And when you search for the specific card you want that vessel to pop out on top.
There are two ways to do it:
You have to run through the array, find the index of that vessel and do whatever it takes to manipulate your array and to make that item at top and re-render your list.
Alternatively render one more component on top of your vessel list as user clicks the search button. You just have to find the item index and render it. This way you don't have to deal with array manipulation. It doesn't matter if you have 80 or 1000 cards.
Please checkout official documentation for array methods, for array slicing and splice.
Hope this is what you are looking for. If you need further help, comment please.

Categories

Resources