Mapping Array of Objects React - javascript

So I am currently having a little problem here. So I have this Component that is taking data from JSON, I have Link but is showing the like 20 times more. The same amount of objects that I have in JSON file. I know this is the problem {data.map((postData), it is mapping all the objects in JSON file, when I want that the only (classE, priceE and imageE) to show.
import React from "react";
import data from "./data.json";
import { Link } from "react-router-dom";
function E() {
return (
<div>
{data.map((postData) => {
return (
<div key={postData.id} className="m-4 bg-blue-100 rounded-xl p-8 ">
<div>
<Link
to={`/payment/${postData.id}`}
className="py-1 px-2 text-black-600 h-10 ml-24 mt-32 bg-white w-
36 rounded-full focus:outline-none focus:ring-2 focus:ring-gray-600"
>
Buy Now
</Link>
<img
alt=""
className="w-screen object-contain"
src={postData.imageE}
></img>
<h1 className=" ml-24 md:text-5xl sm:text-5xl top-8">
{postData.classE}
</h1>
<h1 className="text-base font-mono ml-24 top-24">
{postData.priceE}
</h1>
</div>
</div>
);
})}
</div>
);
}
export default E;
JSON file
[
{
"id": 0,
"class": "A-Class",
"Info": "A is the cheapest one ",
"imageA": "./ModImages/Aclass.jpg",
"textA": "fdsd",
"trefuA": "fdsd",
"optionA": "fdsd"
},
{
"id": 1,
"classE": "E-Class",
"imageE": "./ModImages/Eclass.jpg",
"priceE": "$43,600"
}
]

Try this :
{data.filter(d =>
d.classE &&
d.imageE &&
d.priceE) //FILTER FIRST
.map((postData) => { //THEN MAP
//CODE HERE
})
}
You filter the data first, then you map it

If you want to display only the objects with the properties classE, imageE, and priceE, you need to filter out the objects you are not interested in.
Change this line:
{data.map((postData) => {
to:
{data.filter(d =>
d.hasOwnProperty('classE') &&
d.hasOwnProperty('imageE') &&
d.hasOwnProperty('priceE'))
.map((postData) => {
That will display only the objects you want.

Related

Add routing to navbar (react & tailwind)

import { useState } from "react";
const App = () => {
const [open, setOpen] = useState(true);
const Menus = [
{ title: "Home", src: "0" },
{ title: "Site1", src: "1", gap: true },
{ title: "Site2 ", src: "2" },
{ title: "Site3", src: "3" },
{ title: "Site4", src: "4" }
];
return (
<div className="flex">
<div
className={` ${
open ? "w-72" : "w-20 "
} bg-gray-800 p-5 pt-8 sticky top-0 left-0 h-[930px] duration-300`}
>
<img
src="./src/assets/control.png"
className={`absolute cursor-pointer -right-3 top-9 w-7 border-dark-purple
border-2 rounded-full ${!open && "rotate-180"}`}
onClick={() => setOpen(!open)}
/>
<div className="flex gap-x-4 items-center">
<img
src="./src/assets/logo.png"
className={`cursor-pointer duration-500 ${
open && "rotate-[360deg]"
}`}
/>
<h1
className={`text-white origin-left font-medium text-xl duration-200 ${
!open && "scale-0"
}`}
>
Site
</h1>
</div>
<ul className="pt-6">
{Menus.map((Menu, index) => (
<li
key={index}
className={`flex rounded-MD p-2 cursor-pointer hover:bg-light-white text-gray-300 text-sm items-center gap-x-4
${Menu.gap ? "mt-9" : "mt-2"} ${
index === 0 && "bg-light-white"
} `}
>
<img src={`./src/assets/${Menu.src}.png`} />
<span className={`${!open && "hidden"} origin-left duration-200`}>
{Menu.title}
</span>
</li>
))}
</ul>
</div>
This is the code that I got after following this tutorial: Tutorial
How can I link my other pages with the navbar? So clicking for example Site1 will direct the user to Site1?
The problem is that I can't use tags or hfref in this case and I have no idea how to solve my problem as I'm just learning react.
Multiple things you can do here.
If you want to stick with clickable buttons, you could use React Router and the, for each Menu add an onClick={() => router.push(Menu.title)} (subject to whatever your actual url is).
Otherwise, in a more native way, you could use a tags instead of span tags, which can receive href={Menu.title}. The downside here is that you'd have to style them again, as a tags have browser-specific default styles.
Have a look and read into the React-router: https://reactrouter.com/en/main/getting-started/tutorial
To create a link use the tag instead of the tag

Cannot read properties of undefined (reading 'map') react JS

I am trying to make a blog using ReactJS and NextJS in VS Code I don't have any error but when I run it it shows in browser: " TypeError: Cannot read properties of undefined (reading 'map') "
So this is the code
import React, { useState, useEffect } from 'react';
import Image from 'next/image';
import moment from 'moment';
import Link from 'next/link';
import { getSimilarPosts, getRecentPosts } from '../services';
const PostWidget = ({ categories, slug }) => {
const [relatedPosts, setRelatedPosts] = useState([]);
useEffect(() => {
if (slug) {
getSimilarPosts(categories, slug).then((result) => {
setRelatedPosts(result);
});
} else {
getRecentPosts().then((result) => {
setRelatedPosts(result);
});
}
}, [slug])
console.log(relatedPosts)
return (
<div className="bg-white shadow-lg rounded-lg p-8 pb-12 mb-8">
<h3 className="text-xl mb-8 font-semibold border-b pb-4">{slug ? 'Related Posts' : 'Recent Posts'}</h3>
{relatedPosts.map((post) => (
<div key={post.title} className="flex items-center w-full mb-4">
<div className="w-16 flex-none">
<img
alt={post.title}
height="60px"
width="60px"
unoptimized
className="align-middle rounded-full"
src={post.featuredImage.url}
/>
</div>
<div className="flex-grow ml-4">
<p className="text-gray-500 font-xs">{moment(post.createdAt).format('MMM DD, YYYY')}</p>
<Link href={`/post/${post.slug}`} className="text-md" key={index}>{post.title}</Link>
</div>
</div>
))}
</div>
);
};
export default PostWidget;
And this is where the error is.
{relatedPosts.map((post) =>
use ? make in this code:
{relatedPosts?.map((post) =>
Check relatedPosts has data before rendering map.
If not working please share getSimilarPosts, getRecentPosts
{
relatedPosts &&
relatedPosts.length > 0 &&
relatedPosts.map((post) => (
...
))
}

React - "Functions are not valid as a React child" when I return text from a function

I am learning React.js and I am not sure what is happening here. I want to have a function that returns a string isWaterBoiling() depending on the value of a variable. Then I want to render that string in UI but I am getting this error. I dont understand why this is happening, it doesnt make sense:
Warning: Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.
at div
Here is my code:
import { useState } from "react"
const App = () => {
const [celsius, setCelsius] = useState()
const [fahrenheit, setFahrenheit] = useState()
const calculateFahrenheit = newCelsius => {
setCelsius(newCelsius)
setFahrenheit(((newCelsius * 9 / 5) + 32).toFixed(2))
}
const calculateCelsius = newFahrenheit => {
setFahrenheit(newFahrenheit)
setCelsius(((newFahrenheit - 32) * 5 / 9).toFixed(2))
}
const isWaterBoiling = () => {
return (parseFloat(celsius >= 100))
? "boiling"
: "not boiling"
}
return (
<div className="bg-gray-800 h-full text-gray-300 p-4 text-center">
<div className="font-semibold">Temperature Calculator</div>
<div className="mt-4 space-y-4">
<div className="flex gap-3 items-center">
<span className="flex-[5] text-right">Celsius:</span>
<input
value={celsius}
onChange={event => calculateFahrenheit(event.target.value)}
className="flex-[7] bg-gray-700 rounded-sm py-1 px-3"
type="text"
/>
</div>
<div className="flex gap-3 items-center">
<span className="flex-[5] text-right">Fahrenheit:</span>
<input
value={fahrenheit}
onChange={event => calculateCelsius(event.target.value)}
className="flex-[7] bg-gray-700 rounded-sm py-1 px-3"
type="text"
/>
</div>
</div>
<div className="mt-4 italic text-gray-400">
The water is { isWaterBoiling }
</div>
</div>
)
}
export default App
As the error mentions, you are not calling your isWaterBoiling function, but returning it. You need to change that bit of code to The water is { isWaterBoiling() }

Button Function Not calling From Another file in React

I need to call CutomerDashboard.js file's "toggleIsTrucated" function and "isTruncated" to CustomerNotice.js files button onClick and text change places, How can I call that?
(In this customer dashboard file I'm creating a Read function to show some extent of notice text)
import React, {useState,useEffect} from 'react';
import { Input, Row, Col, Button } from 'antd';
import {fetchDashboardMetrics} from "./DashboardApi";
import {items} from "./DashboardItems";
import axios from 'axios';
import CustomerNotice from "./CustomerNotice";
function Read ({children}) {
const text = children;
const [isTruncated, setIsTrucated] = useState(true);
const result = isTruncated ? text.slice(0,90) : text;
function toggleIsTrucated(){
setIsTrucated(!isTruncated);
}
return (
<div>
{result}....
</div>
);
}
const CustomerDashboard = () => {
const [features, setFeatures] = useState(items);
const source = axios.CancelToken.source()
const [notice, setNotice] = useState(<Read>Customer Notice: Optimism Is Invaluable For The Meaningful Life. With A Firm Belief In A Positive Future You Can Throw Yourself Into The Service Of That Which Is Larger Than You Are. -Martin Seligman-</Read>);
const [noticeVisibility, setNoticeVisibility] = useState(true);
useEffect(() => {
fetchDashboardMetrics(features, setFeatures,source.token)
return (() => {
source.cancel();
})
}, []);
return (
<>
<div className='md:pl-8 sm:pl-0'>
<div className='my-5 '>
<p className='mb-8'>My Account - Dashboard Overview</p>
{noticeVisibility && <CustomerNotice notice={notice} setNoticeVisibility={setNoticeVisibility}/>}
</div>
<ul role="list" className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
{features.map((feature) => (
<li key={feature.name} className="col-span-1 bg-white rounded-lg shadow divide-y divide-gray-200 relative">
<div className="w-full flex items-center justify-between p-6 space-x-6">
<div className="flex-1 truncate">
<div className="flex items-center space-x-3 justify-between">
<h3 className="text-gray-900 text-lg truncate">{feature.name}</h3>
{feature.isNew && (
<div className="absolute -top-2 -right-2 p-1 px-4 text-white text-sm bg-red-500">
New
</div>
)}
</div>
</div>
</div>
<div>
<div className={'mx-4 mt-2 mb-3 '}>
{feature.details.map((singleDetail) => {
return (
<div className={'flex justify-between text-base'}>
<span>{singleDetail.name}</span>
<span>{singleDetail.value}</span>
</div>
)
})}
</div>
</div>
</li>
))}
</ul>
</div>
</>
)
}
export default CustomerDashboard;
import React, {useState,useEffect} from 'react';
import {XIcon} from "#heroicons/react/solid";
const CustomerNotice = ({notice, setNoticeVisibility}) => {
return (
<div>
<div className="mt-8 pb-2 sm:pb-5">
<div className="max-w-7xl mx-auto px-2 sm:px-6 lg:px-8">
<div className="p-2 rounded-lg bg-orange-600 shadow-lg sm:p-3">
<div className="flex items-center justify-between flex-wrap">
<div className="w-0 flex-1 flex items-center">
<p className="ml-3 font-medium text-white truncate">
<span className="md:inline">{notice}</span>
</p>
</div>
<div className="order-3 mt-2 flex-shrink-0 w-full sm:order-2 sm:mt-0 sm:w-auto">
<a
href="#"
className="flex items-center justify-center px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-orange-600 bg-white hover:bg-orange-50"
>
<button onClick={toggleIsTrucated}>{isTruncated ? "Read More" : "Read Less"}</button>
</a>
</div>
<div className="order-2 flex-shrink-0 sm:order-3 sm:ml-2">
<button
onClick={() => setNoticeVisibility(false)}
type="button"
className="-mr-1 flex p-2 rounded-md hover:bg-orange-500 focus:outline-none focus:ring-2 focus:ring-white"
>
<span className="sr-only">Dismiss</span>
<XIcon className="h-6 w-6 text-white" aria-hidden="true"/>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default CustomerNotice;
If this is not possible please suggest me a possible way.
Instead of doing a bunch of hacks, I would recommend simplifying the structure of your components.
import { useState } from 'react'
export default function CustomerDashboard() {
// I am not sure why you want to keep notice in state,
// because in your example you did not call setNotice
const [notice, setNotice] = useState(`
Customer Notice: Optimism Is Invaluable For The Meaningful Life.
With A Firm Belief In A Positive Future You Can Throw Yourself Into The Service
Of That Which Is Larger Than You Are. -Martin Seligman
`)
const [isNoticeVisible, setIsNoticeVisible] = useState(true)
return (
<div>
<h1>My Account - Dashboard Overview</h1>
{isNoticeVisible && (
<CustomerNotice
notice={notice}
setIsNoticeVisible={setIsNoticeVisible}
/>
)}
</div>
)
}
function CustomerNotice(props) {
const { notice, setIsNoticeVisible } = props
const [isTruncated, setIsTruncated] = useState(true)
function toggleIsTruncated() {
setIsTruncated(!isTruncated)
}
return (
<div>
<Read text={notice} isTruncated={isTruncated} />
<button onClick={toggleIsTruncated}>
{isTruncated ? 'Read More' : 'Read Less'}
</button>
<button onClick={() => setIsNoticeVisible(false)}>Dismiss</button>
</div>
)
}
function Read(props) {
const { text, isTruncated } = props
const result = isTruncated ? text.slice(0, 90) : text
return <div>{result}....</div>
}
List of the things that were bad in your code.
Keeping the component instance in the state. It is hard to manage. Even your simple case proves that.
Keeping the toggleIsTruncated function inside the Read component. I think we should keep it outside and pass only 2 props to the Read component. I enable exposed only two things
const { text, isTruncated } = props
As you can see it is easy to maintain and allow us to do whatever we want.
PS. If my review and example were helpful please leave the thumbs up.

React : Firing a custom alert from multiple components using an existing component having its own styles

I am looking to make my alert() more user friendly. I have 3 components which fit together before an alert is trigger.
I have a form (dropdown and input) which on submit fires the following function:
// src/components/input.js
<Btn onClick={() => getData(this.state.dropdown, this.state.value)}>Generate</Btn>
getData() is the following function which is in a separate file ../utils/debugger
// src/utils/debugger
async function getData(filter, captureName) {
if (captureName === '') {
alert(<Alert color='red' type='warning' message='this is an error' />);
} else {
axios({
method: 'GET',
url: `http://xxx/debugger/${filter}/${captureName}/logs`,
})
.then((res) => {
if (res.data.length === 0) {
alert(<Alert color='red' type='warning' message='this is an error' />);
} else {
alert(<Alert color='green' type='success' message='this is an error' />);
console.log(res.data);
data = res.data;
}
return res.data;
})
.catch((err) => {
console.log(err);
});
}
}
But I would like to use the alerts above to present my <Alert /> components in the following file:
// src/App.js
ReactDOM.render(
<React.StrictMode>
<script src='http://localhost:8097'></script>
<div className='flex flex-col min-h-screen'>
<header>
<nav className='bg-gray-800'>
<div className='mx-auto px-8'>
<div className='flex items-center justify-between h-20'>
<div>
<span className='text-white font-bold'>Easy Debugger UI</span>
</div>
<div className=''>
<Input /> // ../src/components/input.js
</div>
</div>
</div>
</nav>
</header>
<div className='container mx-auto'>
<div className='my-2'>
<Alert color='red' type='warning' message='waaaah' /> // display my alert here.
</div>
<main>
<App />
</main>
</div>
<footer className='mt-10'></footer>
</div>
</React.StrictMode>,
document.getElementById('root')
);
I have tried to use the alert() but this just gives me the standard popup with [object object]
any ideas how i can get all these 3 files to talk to each to fire off the alerts when the conditionals are met in getData()
This is my Alert component...i want to keep this the way it is
import React from 'react';
export const Alert = ({ color, type, message }) => {
const [showAlert, setShowAlert] = React.useState(true);
function AlertType(props) {
const alertType = props.alertType;
if (alertType === 'success') {
return (
<span role='img' className='text-3xl'>
🎉
</span>
);
}
if (alertType === 'warning') {
return (
<span role='img' className='text-3xl'>
😱
</span>
);
}
}
return (
<>
{showAlert ? (
<div
className={
'text-white px-6 py-4 border-0 rounded relative mb-4 bg-' + color + '-500 flex items-center'
}>
<span className='text-xl inline-block mr-5 align-middle'>
<AlertType alertType={type} />
</span>
<span className='inline-block align-middle mr-8'>
<b className='uppercase'>{type}! </b>
<span className='capitalize'>{message}</span>
</span>
<button
className='absolute bg-transparent text-2xl font-semibold leading-none right-0 top-0 mt-4 mr-6 outline-none focus:outline-none'
onClick={() => setShowAlert(false)}>
<span>×</span>
</button>
</div>
) : null}
</>
);
};
export default Alert;
You can use the Alert component provided in question with minor modification using react-universal-flash as below
Just use it as a child of the Flasher Component
export const Alert = ({ content, type, deleteFlash}) => {
const {color,inpType} = type;
function AlertType(props) {
const alertType = props.alertType;
if (alertType === 'success') {
return (
<span role='img' className='text-3xl'>
🎉
</span>
);
}
if (alertType === 'warning') {
return (
<span role='img' className='text-3xl'>
😱
</span>
);
}
}
return (
<div
className={
'text-white px-6 py-4 border-0 rounded relative mb-4 bg-' + color + '-500 flex items-center'
}>
<span className='text-xl inline-block mr-5 align-middle'>
<AlertType alertType={inpType} />
</span>
<span className='inline-block align-middle mr-8'>
<b className='uppercase'>{inpType}! </b>
<span className='capitalize'>{content}</span>
</span>
<button
className='absolute bg-transparent text-2xl font-semibold leading-none right-0 top-0 mt-4 mr-6 outline-none focus:outline-none'
onClick={deleteFlash}>
<span>×</span>
</button>
</div>
);
};
export default Alert;
//Import it and use it as child of Flasher from react-universal-flash
<Flasher>
<Alert>
</Flasher>
You can change the position prop of flasher to position it anywhere in page like "top_left","top_right" etc
While firing the messages you can import flash and pass parameters based on the custom type in your alert
// src/utils/debugger
async function getData(filter, captureName) {
if (captureName === '') {
flash("this is an error",6000,{color:"red":inpType:"warning"})
} else {
axios({
method: 'GET',
url: `http://xxx/debugger/${filter}/${captureName}/logs`,
})
.then((res) => {
if (res.data.length === 0) {
flash("this is an error",6000,{color:"red":inpType:"warning"})
} else {
flash("this is an error",6000,{color:"green":inpType:"success"})
console.log(res.data);
data = res.data;
}
return res.data;
})
.catch((err) => {
console.log(err);
});
}
}
You can't pass a React component to alert(). alert() expects a string.
You can use react tostify to show alerts!!
First, install it:
npm install --save react-toastify
In your app.js:
import React from 'react';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
// minified version is also included
// import 'react-toastify/dist/ReactToastify.min.css';
function App(){
const notify = () => toast("Wow so easy !");
return (
<div>
<button onClick={notify}>Notify !</button>
<ToastContainer />
</div>
);
}
Remember to render the ToastContainer once in your application tree. If you can't figure out where to put it, rendering it in the application root would be the best bet.
After that you can import and call toast function where ever you want.
Read more on it here.

Categories

Resources