Can't access nested Objects JSON in React JSX - javascript

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.

Related

React Server-side rendering error due to mismatch between client and server

I am working on a React app (18.2.0 version to be exact), which uses server side rendering. On one of the pages, I am getting a following error:
Code of the component:
<div className="O111-color-module O111-color-module--multi container is-opened" suppressHydrationWarning={true}>
<div className="O111-color-module-filters container">
{colorsData.colorFilters.map((filter, index) => <div key={index} className="O111-color-module-card offset-383">
<h2 className="O111-color-module-filters__header">{props.header}</h2>
<BaseSelect handleChange={handleFilterChange} selectedValue={selectedFilterGroup} options={getColorGroupOptions(filter)} label={filter.label} />
</div>)}
</div>
<div className="card-list--swipe-stack-cards">
<div className={`card details ${mobileFullScreenDetails && 'O111-color-module--multi-details-block'}`}>
<div className="O111-color-module--multi-details has-value">
<div className="O111-color-module--multi-details-top">
<div className={`O111-color-module--multi-details-top is-${selectedColor.colorType}`}>
<div className="O111-color-module--multi-details-color"
style={{ backgroundImage: `url('${selectedColor.previewColorImage}')` }}>
<h3>{selectedColor.colorName}</h3> {/*<---This is where the error is being thrown*/}
</div>
<div className="O111-color-module--multi-details-info">
<ColorProperties {...props} color={selectedColor} />
</div>
<button className="modal__close js-modal__close" onClick={() => setMobileFulscreenDetails(false)} />
{selectedColor.matchingColors && selectedColor.matchingColors.length > 0 &&
<div className="O111-color-module--multi-details-matching-colors">
<h4>{props.matchingColorsLabel}</h4>
<div className="O111-color-module--multi-details-matching-colors-container">
{selectedColor.matchingColors.map((matchingColor, index) =>
<div key={index}
className={`is-${matchingColor.colorType}`}
onClick={() => handleColorSelection(matchingColor.id)}
style={{ backgroundImage: `url('${matchingColor.colorImage}')` }}>
<span> {matchingColor.colorCode} </span>
</div>
)}
</div>
</div>}
</div>
</div>
<div className="O111-color-module--multi-details-bottom">
{getColorSampleOrder()}
</div>
</div>
</div>
</div>
I have added the suppressHydrationWarning={true} prop to the most outer div in the component, but it didn't make the error go away.
Anybody knows what exactly is causing the problem and why is there mismatch between client and server? I am not using Next.js (most questions with SSR-related problems in React are in apps which are using it).

how to pass values from an array into a prop

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 (
// ...
// ...
// ...
);
}

TypeError: Cannot destructure property 'title' of 'tracks[trackIndex]' as it is undefined - ReactJS

I want to set the track index to the queue number of song but with setTrackIndex I'm getting a type error and I can't manipulate trackIndex directly because it's a constant variable. is there any way I can do what i do. this is what I'm trying but getting the error.
const [trackIndex, setTrackIndex] = useState(0)
const { title, artist, image, audioSrc } = tracks[trackIndex]
var i = 0
{tracks.map(track => {
i++
return (
<div className="song-details-artwork queue-next">
<div className="art">
<img style={{ width: "100%" }} src={track["image"]} alt="" />
</div>
<div onClick={() => {setTrackIndex(i)} className="song-names">
<div className="queue-song-name">{track["title"]}</div>
<div className="queue-song-name">{track["artist"]}</div>
</div>
</div>
)
})}
As the comments mention, you should handle the undefined case (elsewhere, not in the component where you are doing the render), i.e., when your tracks is undefined or null.
While this code can handle an empty array... it would just show nothing, so it would be great to have some debugging available with you.
Your code can be slightly improved to:
{tracks.map((track,index)=> (
<div className="song-details-artwork queue-next">
<div className="art">
<img style={{ width: "100%" }} src={track["image"]} alt="" />
</div>
<div onClick={() => {setTrackIndex(index)} className="song-names">
<div className="queue-song-name">{track["title"]}</div>
<div className="queue-song-name">{track["artist"]}</div>
</div>
</div>))}

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