Array mapping is always not a function - javascript

I've been fiddling with arrays and mapping them using the Array.prototype.map() fucntion and honestly i've been struggleing ALOT so i hope somebody can share some light on this.
So my goal is simple to map some headings and rows in a table in my custom component, but when i get to make the mapping its always says "variable.map() is not a function" event tho im specifying its an array and it has values im passing on from my page.
I have already tested if its was because it was empty but it doesnt seem that way.
My page is simply this for now.
import AppLayout from '../../../components/AppLayout';
import Table from '../../../components/modules/Table';
export default function Products() {
return (
<AppLayout>
<section className="content">
<h3 className="text-3xl font-bold">Products</h3>
<Table
headings={[
'',
'Product',
'Status',
'Type',
]}
/>
</section>
</AppLayout>
);
}
As for my table its:
export default function Table(headings = [], rows = {}) {
const top = headings.map((value) => (
<th
key={value}
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
{value}
</th>
));
return (
<div className="flex flex-col">
<div className="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
<div className="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
<div className="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
{top}
</thead>
<tbody>
{rows}
</tbody>
</table>
</div>
</div>
</div>
</div>
);
}
I've had other issues with mapping arrays but this is the most one i always fail one idk why SO ANNOYING.
Thanks in advance

I checked your mapping and it works fine. I think the problem is with your data extraction. You should modify your code as follow:
export default function Table({headings = [], rows = {}}) {
or
export default function Table(props) {
{headings, rows} = props;

Component props will always be an object, so you need to destructure the properties from that object:
Table({ headings = [], rows = [] })
I've changed rows to an array too because, although you don't pass any row property into that component at the moment, I'm pretty sure that it will also be an array that will also need to be mapped over.

Related

an array of the time-when the user has clicked on the button.. but the value keeps on changing...Javascript

I want to make an array of the time-when the user has clicked on the button.. but the value keeps on changing...
In the image, only the current time is shown in the array-but i want the list of timess-when the user clicked on the button.. I normally push.. array.push(element) which i used here as well.But it doesnt work..Why is this ?
Plus i used the hydration states and functions to prevent hydration which was occuring .
import React, { useEffect, useState } from 'react'
function Clock() {
const [time, setTime] = useState(new Date().toLocaleTimeString())
const [isHydrated,setIsHydrated] = useState(false);
let startTime=[];
useEffect(() => {
setIsHydrated(true);
}, [])
setTimeout(()=>{
setTime(new Date().toLocaleTimeString())
},1000)
if(!isHydrated) {
return null;
}
const updateElement = (time) =>{
startTime.push(time);
console.log(startTime)
}
return (
<div>
<div className='container flex flex-col'>
<h1 className="text-red-500 p-10">Productivity app</h1>
<div>
<div>
<span className='p-5 font-bold'>time : {time}</span>
</div>
<button
onClick={()=>updateElement(new Date().toLocaleTimeString()) }
className='bg-red-500 hover:bg-red-700 p-10 w-2/5 text-white rounded-full'>Start</button>
</div>
<div className="overflow-x-auto relative mt-5">
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400">
<thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
</div>
</div>
</div>
)
}
export default Clock
`
Well, i had looked at some ways.. i want the list of the times when the user clicked on the button so that- i could list them.
In every render the setTimeout will be called and it will create a new timer that will kick in and change the time value

React returns Typerror whenever i add api content

Hi i am making a photography portfolio with strapi as my CMS and graphql to fetch data in my React frontend
the problem is whenever i add a new pic using strapi the entire site crashes and returns
Uncaught TypeError: Cannot read properties of undefined (reading 'gears')
but when i edit Gearfetch variable by removing it and rewriting it all again it starts working untill i add another pic via strapi and then it gives same error again
is there a permanent solution to this ?
my gearfetch.js :
import React from "react";
import { gql, useQuery } from "#apollo/client";
import MyGear from "../pages/MyGear";
function Gearfetch() {
const Geardata = gql`
query Getgears {
gears {
data {
id
attributes {
Name
description
image {
data {
attributes {
formats
}
}
}
}
}
}
}
`;
const data = useQuery(Geardata);
const GearFetch = data.data.gears.data //<-- to fix i have to remove and rewrite this again
console.log(GearFetch)
return (
<div className="">
<div >
<div className="flex justify-center font-mono font-extrabold text-lg mt-6 ">
MyGear
</div>
<div className="flex justify-center">
<div className=" p-4 xl:mt-4 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 md:gap-2 md:p-4 ">
{GearFetch.map((Gears) => (
<div className="p-4">
<MyGear
key={Gears.attributes.Name}
name={Gears.attributes.Name}
description={Gears.attributes.description}
image = {Gears.attributes.image.data[0].attributes?.formats?.medium.url}
/>
</div>
))}
</div>
</div>
</div>
</div>
);
}
export default Gearfetch;

Next.js - Expected server HTML to contain a matching <div> in <div>

Live example available here
I'm trying to make a basic layout where, on mobiles, only the latest posts appear. On desktop, the left column should be the posts and the right column the top categories and most popular posts.
Here is the layout:
const IndexLayout: React.FC<IndexLayoutProps> = ({}) => {
const cols = useScreenType()
return cols === '2-cols' ? (
<div className="w-full flex justify-between items-start">
<ListPosts data-comp="ListPosts" className="w-4/6" />
<div className="sticky ml-12 w-2/6 flex flex-col">
<TopCategories data-comp="TopCategories" className="w-full" />
<PopularPosts data-comp="PopularPosts" className="mt-4" />
</div>
</div>
) : (
<ListPosts data-comp="ListPosts" className="w-full" />
)
}
Here's the useScreenType hook:
import { useMediaQuery } from 'react-responsive'
export const useScreenType = () => {
const is2Cols = useMediaQuery({ minWidth: 1300 })
const is1Cols = useMediaQuery({ minWidth: 800 })
if (is2Cols) {
return '2-cols'
}
if (is1Cols) {
return '1-cols'
}
return 'fullscreen'
}
And I keep getting this error:
Warning: Expected server HTML to contain a matching <div> in <div>.
div
ListPosts#webpack-internal:///./components/posts/ListPosts.tsx:31:19
div
IndexLayout#webpack-internal:///./components/layout/IndexLayout.tsx:28:149
div
Index#webpack-internal:///./pages/index.tsx:24:149
ApolloProvider#webpack-internal:///./node_modules/#apollo/client/react/context/ApolloProvider.js:13:18
s#webpack-internal:///./node_modules/next-apollo/dist/index.es.js:26:1911
div
div
MyApp#webpack-internal:///./pages/_app.tsx:37:19
ErrorBoundary#webpack-internal:///./node_modules/#next/react-dev-overlay/lib/internal/ErrorBoundary.js:23:47
ReactDevOverlay#webpack-internal:///./node_modules/#next/react-dev-overlay/lib/internal/ReactDevOverlay.js:73:20
Container#webpack-internal:///./node_modules/next/dist/client/index.js:155:20
AppContainer#webpack-internal:///./node_modules/next/dist/client/index.js:643:18
Root#webpack-internal:///./node_modules/next/dist/client/index.js:779:19
Now I think the issue is due to the useScreenType hook not being able to get a width because window isn't defined on the server. But how can I fix this issue? And not only do I get an error, but my HTML renders weirdly.
The final render ends up being something like this (when it renders as '2-cols'):
<div class="flex flex-col justify-start items-start w-full">
<div class="mt-6 w-full"></div>
<div class="mt-4 flex items-center cursor-pointer transform transition hover:scale-105 text-sm">
<div class="w-full p-6 rounded-lg flex flex-col dark:bg-gray-800 shadow-md"></div>
<div class="mt-4 p-6 rounded-lg flex flex-col dark:bg-gray-800 shadow-md"></div>
</div>
</div>
Note: I am using Next.js v10.2.0
Code can be found on GitHub
As you notice, you cant access window object on server, so if you want to server-render something based on window object - you must hardcode these values.
The only thing you can rely on is user-agent in request headers, which gives you some understanding of user device.
For example this way you can detect user device in _app.js:
const device = deviceDetector.detect(isServer() ? ctx.req.headers['user-agent'] : window.navigator.userAgent)
deviceDetector is any kind of device detection implementation based on user agent
For anyone wondering how I fixed this, I ditched the responsive design with logic and switched to CSS. Here is my layout post fix (changed some classes with the lg prefix [documentation]):
const IndexLayout: React.FC<IndexLayoutProps> = ({}) => {
return (
<div className="mt-12 lg:mt-24 w-5/6 mx-auto flex items-start">
<div className="w-full flex justify-between items-start">
<ListPosts className="lg:w-4/6 w-full" />
<div className="hidden sticky ml-12 w-2/6 lg:flex flex-col">
<TopCategories className="w-full" />
<PopularPosts className="mt-4" />
</div>
</div>
</div>
)
}

Search bar searching combined API React

Im making a small school project with a react frontend showing different characters from tv shows/movies.
I printed these chars out into some tabels, fetched from 3 different APIs (Harry Potter, Star Wars and GoT)
On the frontpage of the site i want to have a search bar function where you can search for characters in all 3 apis and show them in a table/modal (doesnt matter for now) Therefor i combined the 3 APIs into one endpoint containing them all in an array
Im having some troubles making this search bar function. I want to have a search bar where can write part of the name of a character and it will suggest or show a character based on that (ex. Harr should show/suggest Harry Potter)
So far my code looks like this:
export default function Search({ searchingForChar }) {
const init = [{ name: "", fullName: "" }];
const [allCharacters, setAllCharacters] = useState(init);
const fetchData = () => {
console.log("test");
if (searchingForChar !== "" || searchingForChar !== undefined) {
searchFacade
.searchForAllChars()
.then((data) =>
setAllCharacters([
...data.swList.results,
...data.hpList.hpDTOList,
...data.gotList.results,
])
);
}
};
useEffect(fetchData, [searchingForChar]);
return (
<>
{allCharacters
.filter((char) => char.name.includes(searchingForChar))
.map((filteredPerson) => (
<>
<h1>Her burde stå et navn: {filteredPerson.name}</h1>
</>
))}
</>
);
}
And is used in the Form here:
export default function Home() {
const [value, setValue] = useState(),
onInput = ({ target: { value } }) => setValue(value),
onFormSubmit = (e) => {
e.preventDefault();
console.log(value);
setValue();
};
return (
<div className="container-fluid padding">
<img className="logo" src={Dachma} alt=""></img>
<div className="row">
<div className="col-3"></div>
<div className="col-6 text-center">
<h4 className="mt-5">Search for your favorite character</h4>
<Form onSubmit={onFormSubmit}>
<Form.Control onChange={onInput} placeholder="Search here.." />
<Form.Text className="text-muted">
Type character name, movie, tv show etc.
</Form.Text>
<MDBBtn
outline
color="primary"
rounded
size="m"
type="submit"
className="mr-auto"
>
Search
</MDBBtn>
</Form>
<Search searchingFor={value} />
</div>
<div className="col-3"></div>
</div>
<div className="row">
<div className="col-2"></div>
<div className="col-8">
<h4 className="mt-5 text-center">Current shows in the site:</h4>
<p className="mt-2 text-muted text-center">
Click to get info about a movie/tv show.
</p>
<div className="flexDirection: row justifyContent: space-between">
<Card imgToDisplay={gotImg} />
<Card imgToDisplay={hpImg} />
<Card imgToDisplay={swImg} />
</div>
</div>
<div className="col-2"></div>
</div>
</div>
);
}
I have tried many different ways found here on stack and other places, i just cant seem to getting it to work as intended
Ive had many different errors but for now im stuck on "Cannot read property 'includes' of undefined.
Can anyone point me in the right direction? Please know that im a beginner to react/JS, so please explain if you can help.

How to loop through objects in JSX react

I have data of nested objects in which I am getting data of my requirement, Now I want to loop through that object and render on UI, But I am not getting Idea how to do that as the UI is fully Dynamically dependent on data.
My data
const countData = {
"current_month": {
"total_employes": 6,
"ariving": "+3",
"exiting": "-1",
"current_month": "April 2020",
"__typename": "CurrentMonthTotalEmp"
},
"previous_month": {
"total_employes": "3",
"arrived": "+2",
"exited": "-2",
"previous_month": "March 2020",
"__typename": "PrevMonthTotalEmp"
},
"__typename": "CurPrevMonthEmps"
}
to make it as array I doing this
const finalData =Object.entries(countData);
Now I want to loop this
please check my code-sandbox for full code
here in my code-sandbox I am rendering statically with HTML
Most of your React applications will use data to render a UI. That's what React excels in.
Step 1: Create a reusable component
You'll have to create a React component which receives the props for each month.
(total_employees, ariving, exiting and current_month) and renders them correctly.
for example:
const MonthComponent = ({ total_employees, ariving, exiting, current_month }) => {
//above return you can alter your data however you want using normal javascript
return (
//in 'return' you can return HTML or JSX to render your component.
<div>
<p>{total_employees}</p>
<p>{ariving}</p>
<p>{exiting}</p>
<p>{current_month}</p>
</div>
);
};
Step 2: Loop over your data and render your reusable component
Now in your parent component you can loop over your array of data.
const ParentComponent = () => {
const countData = {
"current_month": {
"total_employes": 6,
"ariving": "+3",
"exiting": "-1",
"current_month": "April 2020",
"__typename": "CurrentMonthTotalEmp"
},
"previous_month": {
"total_employes": "3",
"arrived": "+2",
"exited": "-2",
"previous_month": "March 2020",
"__typename": "PrevMonthTotalEmp"
},
"__typename": "CurPrevMonthEmps"
}
const months = Object.keys(countData); // ["current_month", "previous_month"]
return (
months.map(month => (
// map over months and render your reusable component for each month
<MonthComponent {...countData[month]} />
))
);
};
Note: Spreading over ...countData[month] is a shorthand property to pass every key-value pair of countData[month] as a prop. I could also have written:
<MonthComponent
total_employees={countData[month].total_employees}
arrived={countData[month].arrived}
exited={countData[month].exited}
previous_month={countData[month].previous_month}
/>
There is a lot of code duplication, we want to reduce that (DRY Principle). First, find the common code that abstractly describes your UI, i.e. a component that has a month/year label, some arrive/exit fields & labels, and an employee count. Convert what you want displayed to a component that takes these "standardized" props.
const MonthData = ({
arrive,
arriveLabel,
exit,
exitLabel,
totalEmployees,
month,
}) => (
<Fragment>
<label className="monthYr" align="left">
{month}
</label>
<div className="row countDiv">
<div className="col-12 col-sm-12 col-md-6 col-lg-6 col-xl-6 total">
<label className="totalHeading">Total employees</label>
<div className="totalCount">{totalEmployees}</div>
</div>
<div className="col-12 col-sm-12 col-md-6 col-lg-6 col-xl-6">
<button className="btn btn-outline-secondary button_Count form-control">
{arriveLabel}
<span className="badge badge-pill badge-primary ml-2">
{arrive}
</span>
</button>
<button className="btn btn-outline-secondary form-control">
{exitLabel}
<span className="badge badge-pill badge-primary ml-2">
{exit}
</span>
</button>
</div>
</div>
</Fragment>
);
I don't think I'd map these as you have different labeling for previous vs. current months, and you only ever display 2 months at a time. Just destructure from the countData the two months' data.
const { current_month, previous_month } = countData;
return (
<div className="row container-fluid">
<div className="form-control graphHeading"> Manpower Graph</div>
<div className="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
<div className="row widthContainer">
<div className="col-12 col-sm-12 col-md-6 col-lg-6 col-xl-6">
<MonthData
arrive={previous_month.arrived}
arriveLabel="arrived"
exit={previous_month.exited}
exitLabel="exited"
month={previous_month.previous_month}
totalEmployees={previous_month.total_employees}
/>
</div>
<div className="col-12 col-sm-12 col-md-6 col-lg-6 col-xl-6">
<MonthData
arrive={current_month.arriving}
arriveLabel="arriving"
exit={current_month.exiting}
exitLabel="exiting"
month={current_month.current_month}
totalEmployees={current_month.total_employees}
/>
</div>
</div>
</div>
</div>
);
You can do something like this in your JSX code:
{finalData.map(value => (
<div>{value.something}</div>
))}
you can use :
{
Object.keys(countData).map(key=>{
const month = countData[key]
return(
//you have access to month
<div>{month.total_employes}</div>
);
})
}
First, you need to convert the countData into a proper structure over which we can run our loop. to do that you need to change how you convert it to array to the following
const finalData = Object.values(countData)
After doing so we can now loop over the finalData variable using a map function like this.
{finalData.map(data => (
<div>{data.total_employes}</div>
<div>{data.ariving}</div>
))}
Moreover to handle missing key/values in the object you can do the following
{finalData.map(data => (
<div>{data.total_employes ? data.total_employes : 'NA'}</div>
<div>{data.ariving ? data.ariving : 'NA'}</div>
))}
Hope this helps

Categories