ReactjS - const loads all states before being fetched - reactjs

Hey guys I am trying to pass a URL for background image into the ResultsItem component. My problem is that the state of places is not defined until data are fetched. The problem is with the const Thumbnail. I always get an error of "TypeError: Cannot read property 'photos' of undefined".
render() {
const Thumbnail = `https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=${places.photos.photoreference}&key=MYAPIKEY
`;
return (
<div>
<div className="flex align-center">
<div className="search">
<SearchInput
id="autocomplete"
placeholder="Search by address"
width="100%"
height={56}
/>
<Script
url="https://maps.googleapis.com/maps/api/js?key=MYAPIKEY&libraries=places,geometry&callback=initAutocomplete"
onLoad={this.handleScriptLoad}
/>
</div>
<div className="current-location">
<Tooltip content="Use current location">
<IconButton
icon="locate"
iconSize={16}
height={32}
onClick={this.currentLocationOnClick}
>
{this.state.lat} & {this.state.lng}
</IconButton>
</Tooltip>
</div>
</div>
<div className="results">
{this.state.places.map(places => (
<div className="results-item" onClick={this.props.sideBarOpen}>
<ResultsItem name={places.name} image={Thumbnail} />
</div>
))}
</div>
</div>
);
}
}

The fact that places is available in an async manner, the best solution is to resolve Thumbnail within the map function itself.
That way it will only be required and resolved when places is available
render() {
return (
<div>
<div className="flex align-center">
<div className="search">
<SearchInput
id="autocomplete"
placeholder="Search by address"
width="100%"
height={56}
/>
<Script
url="https://maps.googleapis.com/maps/api/js?key=MYAPIKEY&libraries=places,geometry&callback=initAutocomplete"
onLoad={this.handleScriptLoad}
/>
</div>
<div className="current-location">
<Tooltip content="Use current location">
<IconButton
icon="locate"
iconSize={16}
height={32}
onClick={this.currentLocationOnClick}
>
{this.state.lat} & {this.state.lng}
</IconButton>
</Tooltip>
</div>
</div>
<div className="results">
{this.state.places.map(places => {
const Thumbnail = `https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=${places.photos.photoreference}&key=MYAPIKEY
`;
return(
<div className="results-item" onClick={this.props.sideBarOpen}>
<ResultsItem name={places.name} image={Thumbnail} />
</div>
)})}
</div>
</div>
);
}
}

You should prevent to load data before they are actually loaded from server, so you should render a loader before use your result in this way:
if(isLoading) { // You should set the loading state before to load data from server
return <span>Loading</span>
}
return ( // This shows your data after loading goes to false
<div>Your code here</div>
)

Related

Update on Async Rendering- ReactJs

Following a tutorial-
Console Warning:
componentWillUpdate has been renamed, and is not recommended for use. Move data fetching code or side effects to componentDidUpdate.Rename componentWillUpdate UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. Please update the following components: Identicon
At first, the app correctly displayed "Welcome Username", but after refreshing I got the warning on the console.
Now, when I type something into Username... and click on Set Nickname nothing happens.
I am expecting to see "Welcome Username"
<div className={styles.welcome}>Wecome {username}</div>
I do not think there is anything wrong with my handleSetUsername function, because it worked previously.
On the Moralis app I see that there are 4 users correctly connected from my Metamask account.
Sidebar.js
const {
isAuthenticated,
nickname,
setNickname,
username,
setUsername,
handleSetUsername,
} = useContext(AmazonContext)
return (
<div className={styles.container}>
<div className={styles.profile}>
{isAuthenticated && (
<>
<div className={styles.profilePicContainer}>
<Image
src={`https://avatars.dicebear.com/api/pixel-art/${username}.svg`}
alt='profile'
className={styles.profilePic}
height={100}
width={100}
/>
</div>
{!username ? (
<>
<div className={styles.username}>
<input
type='text'
placeholder='Username....'
className={styles.usernameInput}
value={nickname}
onChange={e => setNickname(e.target.value)}
/>
</div>
<button
className={styles.setNickname}
onClick={handleSetUsername}
>
Set Nickname
</button>
</>
) : (
<div>
<div className={styles.welcome}>Wecome {username}</div>
</div>
)}
</>
)}
<div className={styles.connectButton}>
<ConnectButton />
</div>
</div>
<div className={styles.menu}>
<Link href='/'>
<div className={styles.menuItem}>
<Image
src={logo}
height={30}
width={30}
className={styles.amazonLogo}
/>
My Amazon
<br /> Board
</div>
</Link>
<div className={styles.menuItem}>
<FaBox />
Collections
</div>
<div className={styles.menuItem}>
<BsFillBookmarkFill />
Saved
</div>
<div className={styles.menuItem}>
<BsFillPersonFill />
Profile
</div>
<Link href='/history'>
<div className={styles.menuItem}>
<AiOutlineHistory />
Transaction History
</div>
</Link>
</div>
<div className={styles.companyName}>
<Image src={logofull} alt='amazon' height={100} width={100} />
</div>
</div>
)
}
export default Sidebar

related to React js (props) css inline style

I want to more than one cards in different background color what i do ?
eg:
import React from "react";
import reactDom from "react-dom";
const BgColor=(props)=>{
return(
<>
<div className="main_div">
<div className="cards" >
<div className="card-side front" >
<div><span>C</span>opy<span>C</span>ode</div>
</div>
<div className="card-side back">
<div><i className="fas fa-copy fs-3" /><br />{props.code}</div>
</div>
</div>
</div>
</>
)
}
export default BgColor;
by pass value in app.js
and so on.....
please help me how to pass value inside the app.js
with this example is hard to to help you. Indeed, we don't know what your props object contains.
Let's assume your props contains
{
name: "toto",
code: "myCode"
}
In order to change background color based on props, you have multiples choices.
You can use dynamics classNames based on your props:
const BgColor=(props)=>{
return(
<>
<div className="main_div">
<div className="cards" >
<div className={`${props.name} card-side front`} >
<div><span>C</span>opy<span>C</span>ode</div>
</div>
<div className="card-side back">
<div><i className="fas fa-copy fs-3" /><br />{props.code}</div>
</div>
</div>
</div>
</>
)
}
See the <div className={${props.name} card-side front} > line. Go to css or scss file for this component and add a class selector inside of it.
In our example, it will be
.toto {
background: red
}
The second option is to inject directly the css inside your div.
Let's assume you send the desired background color inside your propos:
{
backgroundColor: "red",
code: "myCode"
}
In order to that, you have to do this
const BgColor=(props)=>{
return(
<>
<div className="main_div">
<div className="cards" >
<div className="card-side front" style={{backgroundColor: props.backgroundColor}}>
<div><span>C</span>opy<span>C</span>ode</div>
</div>
<div className="card-side back">
<div><i className="fas fa-copy fs-3" /><br />{props.code}</div>
</div>
</div>
</div>
</>
)
}
If you want to know more about css in React, you can check:
https://reactjs.org/docs/faq-styling.html, React.js inline style best practices, https://create-react-app.dev/docs/adding-a-stylesheet/
UPDATE
You can send an array of colors like <BgColor colors={["red", "blue"]} /> then in your BgColor component, you can map on your props like:
const BgColor=({colors})=>{
return (
<div className="main_div">
<div className="cards">
{colors.map((color, index) => {
return (
<div
className="card-side front"
style={{ backgroundColor: color }}
key={index}
>
<div>
<span>C</span>opy<span>C</span>ode
</div>
</div>
);
})}
</div>
</div>
);
}

How to build Tabs component Reactjs

I'm trying to build a Tabs component with ReactJS and I'm following a CSS stylesheet.So, I would love to have this as render :
<div data-container="" class="tabs tabs-horizontal">
<div class="tabs-header">
<div class="tabs-header-tab ph active" data-tab="0" style="transform: translateX(0px) translateZ(0px);">Personal
</div>
<div class="tabs-header-tab ph undefined" data-tab="0" style="transform: translateX(0px) translateZ(0px);">Job
</div>
<div class="tabs-header-tab ph undefined" data-tab="0" style="transform: translateX(0px) translateZ(0px);">
Salary</div>
</div>
<div data-container="" class="tabs-content">
<div data-container="" class="tabs-content-tab open" data-tab="0">
<div>I am a HR Specialist.</div>
</div>
<div data-container="" class="tabs-content-tab undefined" data-tab="0">
<div>No records have been added yet</div>
</div>
<div data-container="" class="tabs-content-tab undefined" data-tab="0">
<div>This type of information needs to be added by your manager</div>
</div>
</div>
</div>
And this is what the components looks like now :
<Tabs>
<TabHeaders>
<TabHeadersItem text="Personal" state="active" />
<TabHeadersItem text="Job" />
<TabHeadersItem text="Salary" />
</TabHeaders>
<TabContents>
<TabContentsItem
content="I am a HR Specialist."
open="open"
/>
<TabContentsItem content="No records have been added yet" />
<TabContentsItem content="This type of information needs to be added by your manager" />
</TabContents>
</Tabs>
So, I'm trying to find a solution, when user clicks on a header it becomes "active" and its content "open" while the others should be closed and not active.
Ok so since you've edited your question, I'll do with mine. The idea is the same: To keep the state of which tab is open, and since you don't want to keep your tabs in a list, then you need to link a TabHeader to a TabContent:
const TabHeaderItem = props => {
return (
<div
onClick={() => props.changeTab(props.text.toLowerCase())}
className={props.state ? "active" : ""}
>
{props.text}
</div>
);
};
const TabContentsItem = props => {
return <div className={props.open ? "open" : "closed"}>{props.content}</div>;
};
const TabComponent = () {
const [active, setActive] = useState("personal");
const changeTab = tab => {
console.log("tab", tab);
setActive(tab);
};
return (
<div className="App">
<div className="tabs">
<TabHeaderItem
changeTab={changeTab}
text="Personal"
state={active === "personal"}
/>
<TabHeaderItem
changeTab={changeTab}
text="Job"
state={active === "job"}
/>
<TabHeaderItem
changeTab={changeTab}
text="Salary"
state={active === "salary"}
/>
</div>
<div className="tabs-content">
<TabContentsItem
content="I am a HR Specialist."
open={active === "personal"}
/>
<TabContentsItem
content="No records have been added yet"
open={active === "job"}
/>
<TabContentsItem
content="This type of information needs to be added by your manager"
open={active === "salary"}
/>
</div>
</div>
);
}
You can check out the working example here: https://codesandbox.io/s/exciting-gauss-lbghq

Cannot read property 'image_url' of undefined in React

I am very new to react and I am trying to show data
but I am getting the error
No Data is appear when i add some code about image_url, title,source_url etc....
TypeError: Cannot read property 'image_url' of undefined
In Recipe.js,
import React, { Component } from 'react'
export default class Recipe extends Component {
render() {
const {
image_url,
title,
source_url,
publisher,
recipe_id
} = this.props.recipe;
return (
<React.Fragment>
<h1>Recipe</h1>
<div className="col-10 mx-auto col-md-6 col-lg-4">
<div className="card">
<img src={image_url} className="img-card-top" style={{height:"14rem"}} alt="recipe" />
<div className="card-body text-capitalize">
<h5>{title}</h5>
<h6 className="text-warning text-slanted">
provided by {publisher}
</h6>
</div>
<div className="card-footer">
<button type="button" className="btn btn-outline-primary">Details</button>
Recipe url
</div>
</div>
</div>
</React.Fragment>
);
}
}
In ReactList.js,
<div className="row">
{recipes.map (recipe => {
return <Recipe key={recipe.recipe_id} recipe={recipe}
/>;
})}
</div>
</div>
<Recipe />
</React.Fragment>
error occur as you use two time <Recipe /> in RecipeList.js,
Removed one <Recipe />,
error will solve
Change
<div className="row">
{recipes.map (recipe => {
return <Recipe key={recipe.recipe_id} recipe={recipe}
/>;
})}
</div>
</div>
<Recipe />
</React.Fragment>
To
<div className="row">
{recipes.map (recipe => {
return <Recipe key={recipe.recipe_id} recipe={recipe}
/>;
})}
</div>
</div>
</React.Fragment>

put elements into variable for naming (react)

I tried to put elements into CustomModal variable:
const CustomModal = (<div className="peoplelistpage-modal">
<div className="peoplelistpage-modal-content-empty" />
<div className="peoplelistpage-modal-content">
<CustomForm
krNameInput={this.state.krNameInput}
handleKrNameInput={this.handleKrNameInput}
enNameInput={this.state.enNameInput}
handleEnNameInput={this.handleEnNameInput}
positionInput={this.state.positionInput}
handlePositionInput={this.handlePositionInput}
departmentInput={this.state.departmentInput}
handleDepartmentInput={this.handleDepartmentInput}
doingInput={this.state.doingInput}
handleDoingInput={this.handleDoingInput}
btnValue="add"
onBtnClick={this.handlePersonAddBtn}
/>
</div>
<div className="peoplelistpage-modal-content-empty" />
</div>);
and used it in render() like this:
render() {
//...
{ CustomModal }
//...
but, got an error:
react-dom.development.js:57 Uncaught Invariant Violation: Objects are not valid as a React child (found: object with keys {CustomModal}). If you meant to render a collection of children, use an array instead.
Is there are any way to put elements into variable for naming?
Thanks.
----update-----
This is my full code of render :
render() {
const CustomModal = (<div className="peoplelistpage-modal">
<div className="peoplelistpage-modal-content-empty" />
<div className="peoplelistpage-modal-content">
<CustomForm
krNameInput={this.state.krNameInput}
handleKrNameInput={this.handleKrNameInput}
enNameInput={this.state.enNameInput}
handleEnNameInput={this.handleEnNameInput}
positionInput={this.state.positionInput}
handlePositionInput={this.handlePositionInput}
departmentInput={this.state.departmentInput}
handleDepartmentInput={this.handleDepartmentInput}
doingInput={this.state.doingInput}
handleDoingInput={this.handleDoingInput}
btnValue="add"
onBtnClick={this.handlePersonAddBtn}
/>
</div>
<div className="peoplelistpage-modal-content-empty" />
</div>);
const { people } = this.props.people.state;
return (
<React.Fragment>
{/* check login */}
{this.props.auth.state.isLoggedIn ? (
{ CustomModal }
) : (
<div />
)}
<div className="peoplelistpage-main">
<h1 className="peoplelistpage-title">people list</h1>
<div className="peoplelistpage-list-container">
{people.map((person, index) => (
<ul className="peoplelistpage-list-ul" key={index}>
<li className="peoplelistpage-list-li">
{`${index + 1}.`}{" "}
<Link to={`${this.props.location.pathname}/${person.id}`}>
{person.kr_name}
</Link>{" "}
<button onClick={this.handlePersonDeleteBtn(person.id)}>
<DeleteUserIcon />
</button>
</li>
</ul>
))}
</div>
<button onClick={this.openModal}>add</button>
</div>
</div>
) : (
<CustomNotPermittedForm />
)}
</React.Fragment>
);
}
Yes, you can use a div or a React.Fragment to group elements together. divs are added to the DOM while Fragments are not. But in order for this work with state, you will have to use a function, as a static variable does not get updated with state values.
const CustomModal = () => (
<React.Fragment> // <-- or div
<div className="peoplelistpage-modal">
<div className="peoplelistpage-modal-content-empty" />
<div className="peoplelistpage-modal-content">
<CustomForm
krNameInput={this.state.krNameInput}
handleKrNameInput={this.handleKrNameInput}
enNameInput={this.state.enNameInput}
handleEnNameInput={this.handleEnNameInput}
positionInput={this.state.positionInput}
handlePositionInput={this.handlePositionInput}
departmentInput={this.state.departmentInput}
handleDepartmentInput={this.handleDepartmentInput}
doingInput={this.state.doingInput}
handleDoingInput={this.handleDoingInput}
btnValue="add"
onBtnClick={this.handlePersonAddBtn}
/>
</div>
<div className="peoplelistpage-modal-content-empty" />
</div>
</React.Fragment>
);
Usage
render() {
// ...
<CustomModal />
// ...

Resources