How to change state every x seconds - javascript

I need to change the name of every avatar every X seconds, I have follow this solution and it works fine but, right now its changing all the names to the same name from RandomAcidName array.
I imagine that I need to iterate through this list also, so each name is passing just once to every avatar.
Here is my code
nameJuggler is passing the name to each avatar
import React, { Component } from "react";
import "./Avatar.scss";
import AcidData from "../Acidsdata/Acids-data.json";
import RandomAcidName from "../../../src/randomAcidName.json";
const getDate = new Date();
const getDay = getDate.getDate();
const getMonth = getDate.getMonth() + 1;
const fullTodayDate = getDay + "/" + getMonth;
const AvatarDisplay = props => {
return (
<div key={props.id} className="container__position-relative">
<img src={props.photo} alt={props.name} className="avatar__img" />
<div className="container__position-absolute avatar__name">
<span>{props.name}</span>
</div>
{props.cumple}
</div>
);
};
class AcidPoblation extends Component {
constructor(props) {
super(props);
this.state = {
sudoNameId: 0,
acidos: AcidData,
randomName: RandomAcidName
};
}
componentDidMount() {
this.changeName = setInterval(() => {
let currentSudoNameId = this.state.sudoNameId;
this.setState({
sudoNameId: currentSudoNameId + 1
});
}, 1500);
}
componentDidUnmount() {
clearInterval(this.changeName);
}
render() {
let nameJuggler =
RandomAcidName[this.state.sudoNameId % RandomAcidName.length];
return (
<main className="container__grid">
{this.state.acidos.map(item => (
<AvatarDisplay
photo={item.acidphoto}
name={nameJuggler}
birth={item.birthdate}
id={item.acidid}
cumple={
item.birthdate === fullTodayDate ? (
<img
src="https://via.placeholder.com/40x40"
alt="feliz cumpleaños"
className="container__position-absolute avatar__birth-date"
/>
) : null
}
/>
))}
</main>
);
}
}
export default AcidPoblation;
Here is the Json with the names
[
"Anderson",
"Ashwoon",
"Aikin",
"Bateman",
"Bongard",
"Bowers",
"Boyd",
"Cannon",
"Cast",
"Deitz",
"Dewalt",
"Ebner",
"Frick",
"Hancock",
"Haworth",
"Hesch",
"Hoffman",
"Kassing",
"Knutson",
"Lawless",
"Lawicki",
"Mccord",
"McCormack",
"Miller",
"Myers",
"Nugent",
"Ortiz",
"Orwig",
"Ory",
"Paiser",
"Pak",
"Pettigrew",
"Quinn",
"Quizoz",
"Ramachandran",
"Resnick",
"Sagar",
"Schickowski",
"Schiebel",
"Sellon",
"Severson",
"Shaffer",
"Solberg",
"Soloman",
"Sonderling",
"Soukup",
"Soulis",
"Stahl",
"Sweeney",
"Tandy",
"Trebil",
"Trusela",
"Trussel",
"Turco",
"Uddin",
"Uflan",
"Ulrich",
"Upson",
"Vader",
"Vail",
"Valente",
"Van Zandt",
"Vanderpoel",
"Ventotla",
"Vogal",
"Wagle",
"Wagner",
"Wakefield",
"Weinstein",
"Weiss",
"Woo",
"Yang",
"Yates",
"Yocum",
"Zeaser",
"Zeller",
"Ziegler",
"Bauer",
"Baxster",
"Casal",
"Cataldi",
"Caswell",
"Celedon",
"Chambers",
"Chapman",
"Christensen",
"Darnell",
"Davidson",
"Davis",
"DeLorenzo",
"Dinkins",
"Doran",
"Dugelman",
"Dugan",
"Duffman",
"Eastman",
"Ferro",
"Ferry",
"Fletcher",
"Fietzer",
"Hylan",
"Hydinger",
"Illingsworth",
"Ingram",
"Irwin",
"Jagtap",
"Jenson",
"Johnson",
"Johnsen",
"Jones",
"Jurgenson",
"Kalleg",
"Kaskel",
"Keller",
"Leisinger",
"LePage",
"Lewis",
"Linde",
"Lulloff",
"Maki",
"Martin",
"McGinnis",
"Mills",
"Moody",
"Moore",
"Napier",
"Nelson",
"Norquist",
"Nuttle",
"Olson",
"Ostrander",
"Reamer",
"Reardon",
"Reyes",
"Rice",
"Ripka",
"Roberts",
"Rogers",
"Root",
"Sandstrom",
"Sawyer",
"Schlicht",
"Schmitt",
"Schwager",
"Schutz",
"Schuster",
"Tapia",
"Thompson",
"Tiernan",
"Tisler"
]
I need that every name is assing just once.
In this link is a replica of my project...

The problem is
let nameJuggler = [this.state.sudoNameId % RandomAcidName.length];
this.state.sudoNameId won't be unique because it's just a number set in the parent component and will be provided to all of the AvatarDisplays not dynamically changing.
An easy fix would just make the .map also have an index so you can add the index to the this.state.sudoNameId which will make each number unique.
See code below
return (
<main className="container__grid">
{this.state.acidos.map((item, index) => {
let nameJuggler =
RandomAcidName[(this.state.sudoNameId + index) % RandomAcidName.length];
return (
<AvatarDisplay
photo={item.acidphoto}
name={nameJuggler}
birth={item.birthdate}
id={item.acidid}
cumple={
item.birthdate === fullTodayDate ? (
<img
src="https://via.placeholder.com/40x40"
alt="feliz cumpleaños"
className="container__position-absolute avatar__birth-date"
/>
) : null
}
/>
)
})}
</main>

Related

Logic of updating an object in react with useState

I have a component renderRoyaltyAccount, that gets rendered x number of times depending on the input that sets royaltyAccount.
In this component I have 2 fields, one for the name of the account, and the second a percentage.
What I wanted to do is depending of the number of accounts to create, create an object with those two fields for each, example :
If he chooses to create two accounts , to have a the end (what I thought but could be not the best choice :) ) :
{
1: {
"account": "test1",
"percentage": 2,
},
2: {
"account": "test#",
"percentage": 0.5
}
}
I tried with a useState and updating it with onChange with inputs, but it was a mess LOL.
If anyone could help me with this state, and specially the logic with objects and hooks. Thank you
export default function FormApp() {
const [royaltyAccount, setRoyaltyAccount] = useState(1);
const [allAccounts, setAllAccounts] = useState ({
{
"account": "",
"percentage": 1,
},
})
const renderRoyaltyAccounts = () => {
let items = [];
for (let i = 0; i < royaltyAccount; i++) {
items.push(
<div key={i}>
<div>
<label>Royalty Account n° {i + 1}</label>
<input onChange={()=> setAllAccounts(???)} type="text"/>
</div>
<div>
<label>Royalty %</label>
<input onChange={()=> setAllAccounts(???)} type="text"/>
</div>
</div>
)
}
return items;
}
return (
<>
<label> Royalty account(s)</label>
<input onChange={(e) => { setRoyaltyAccount(e.target.value)}} type="number"/>
{
renderRoyaltyAccounts()
}
</>
)
}
Dynamically compute the allAccounts state array from the initial royaltyAccount state value. Add an id property to act as a GUID for each account object.
Create a handleRoyaltyAccountChange onChange handler to either append a computed diff of the current allAccounts array length to the new count value, or to slice up to the new count if less.
Create a handleAccountUpdate onChange handler to shallow copy the allAccounts state array and update the specifically matching account object by id.
Give the inputs a name attributeand pass the mappedallAccountselement object's property as thevalue` prop.
Code:
import { useState } from "react";
import { nanoid } from "nanoid";
function FormApp() {
const [royaltyAccount, setRoyaltyAccount] = useState(1);
const [allAccounts, setAllAccounts] = useState(
Array.from({ length: royaltyAccount }).map(() => ({
id: nanoid(),
account: "",
percentage: 1
}))
);
const handleRoyaltyAccountChange = (e) => {
const { value } = e.target;
const newCount = Number(value);
setRoyaltyAccount(newCount);
setAllAccounts((accounts) => {
if (newCount > accounts.length) {
return accounts.concat(
...Array.from({ length: newCount - accounts.length }).map(() => ({
id: nanoid(),
account: "",
percentage: 1
}))
);
} else {
return accounts.slice(0, newCount);
}
});
};
const handleAccountUpdate = (id) => (e) => {
const { name, value } = e.target;
setAllAccounts((accounts) =>
accounts.map((account) =>
account.id === id
? {
...account,
[name]: value
}
: account
)
);
};
return (
<>
<label> Royalty account(s)</label>
<input
type="number"
onChange={handleRoyaltyAccountChange}
value={royaltyAccount}
/>
<hr />
{allAccounts.map((account, i) => (
<div key={account.id}>
<div>
<div>Account: {account.id}</div>
<label>
Royalty Account n° {i + 1}
<input
type="text"
name="account"
onChange={handleAccountUpdate(account.id)}
value={account.account}
/>
</label>
</div>
<div>
<label>
Royalty %
<input
type="text"
name="percentage"
onChange={handleAccountUpdate(account.id)}
value={account.percentage}
/>
</label>
</div>
</div>
))}
</>
);
}

React rendering html elements in nested loops

I have a data structure like this {key: [array of object]}. I want to render each element in array of object using nested for loop like this:
for each entry(k, v) in map:
for each element in array v:
display html data
I am using react version 16.
I tried this in JSX:
class Positions extends React.Component {
renderPosition(position) {
var expiry = position["ExpiryDay"] + "-" + position["ExpiryMonth"] + "-" + position["ExpiryYear"];
console.log(expiry);
return (<label>{expiry}</label>);
}
render() {
return (
<div>
{this.props.positionsGrouped.forEach(function(positions) {
return (
<div>
{positions.map(function(position) {
return (
<div>
{this.renderPosition(position)}
</div>
);
}.bind(this))}
</div>
);
}.bind(this))}
</div>
);
}
}
Here is the JS that it compiles to:
class Positions extends React.Component {
renderPosition(position) {
var expiry = position["ExpiryDay"] + "-" + position["ExpiryMonth"] + "-" + position["ExpiryYear"];
console.log(expiry);
return React.createElement(
"label",
null,
expiry
);
}
render() {
return React.createElement(
"div",
null,
this.props.positionsGrouped.forEach(function (positions) {
return React.createElement(
"div",
null,
positions.map(function (position) {
return React.createElement(
"div",
null,
this.renderPosition(position)
);
}.bind(this))
);
}.bind(this))
);
}
}
However I don't see anything being rendered except for the top most div. Here is the rendered html:
<div id="app">
<div></div>
</div>
Here is what I see in react developer tools:
<App>
<Positions>
<div></div>
</Positions>
</App>
I don't see any errors in the console. I expected at least three nested divs to be rendered however I only see one so it sounds like something is wrong at the level of the first for loop. But, I do see my expiry variable being printed to console properly so I know renderPosition is getting called with the correct data.
Does anyone know what I am doing wrong? I'm new to react and sorry for any typos. Thanks in advance.
this.props.positionsGrouped.forEach would return undefined. I mean it wouldn't return anything. So nothing gets rendered.
Just change your component code like this
import React from "react";
class Positions extends React.Component {
constructor(props) {
super(props);
this.renderPosition = this.renderPosition.bind(this);
}
renderPosition(position) {
var expiry = position["name"] + "-" + position["title"];
console.log(expiry);
return <label>{expiry}</label>;
}
render() {
const { positionsGrouped } = this.props;
return (
<div>
{positionsGrouped.map(positions => {
const keys = Object.keys(positions);
return (
<div>
{positions[keys[0]].map(position => {
return <div>{this.renderPosition(position)}</div>;
})}
</div>
);
})}
</div>
);
}
}
export default Positions;
Inside your parent file
import React from "react";
import ReactDOM from "react-dom";
import Position from "./test";
import "./styles.css";
function App() {
var positionGroup = [
{
a: [
{
name: "hello",
title: "sdfd"
},
{
name: "hello",
title: "sdfd"
},
{
name: "hello",
title: "sdfd"
}
]
},
{
b: [
{
name: "hello",
title: "sdfd"
},
{
name: "hello",
title: "sdfd"
},
{
name: "hello",
title: "sdfd"
}
]
}
];
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<Position positionsGrouped={positionGroup} />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
The return value of forEach is undefined no matter what you return in callback function. use map instead.
class Positions extends React.Component {
getExpiry(position) {
return `${position.ExpiryDay}-${position.ExpiryMonth}-${position.ExpiryYear}`;
}
render() {
return (
<div>
{this.props.positionsGrouped.map(positions => (
<div>
{positions.map((position) => (
<div>
<label>{this.getExpiry(position)}</label>
</div>
))}
</div>
))}
</div>
);
}
}
I changed your code a little to make it more concise.

React - reload external component from App

I'm still new to React.
I'm making a guessing game. On page load, everything loads properly (on Chrome and Safari, at least). The cat buttons are assigned a random number and when clicked, they send the corresponding value to the game logic. When the target number is met or exceeded, the target number resets.
That's what I want, but I also want the buttons to get new values. I want the Buttons component to reload and assign the buttons new values. I've tried using the updating methods found here: https://reactjs.org/docs/react-component.html#updating. I don't know what to do next.
App.js
import React, { Component } from 'react';
import './App.css';
import Buttons from "./components/Buttons/Buttons";
class App extends Component {
targetNumber = (min, max) => {
const targetNum = Math.floor(Math.random()*(max-min+1)+min);
console.log(`Target number = ${targetNum}`);
return targetNum
};
state = {
targetNumber: this.targetNumber(19, 120),
currentValue: 0,
gamesWon: 0,
};
handleClick = (event) => {
event.preventDefault();
const currentValue = this.state.currentValue;
const newValue = parseInt(event.target.getAttribute("value"));
this.setState(
{currentValue: currentValue + newValue}
)
// console.log(newValue);
}
componentDidUpdate() {
if (this.state.currentValue === this.state.targetNumber) {
this.setState(
{
targetNumber: this.targetNumber(19, 120),
currentValue: 0,
gamesWon: this.state.gamesWon + 1
}
)
}
else {
if (this.state.currentValue >= this.state.targetNumber) {
this.setState(
{
targetNumber: this.targetNumber(19, 120),
currentValue: 0,
gamesWon: this.state.gamesWon,
}
);
}
}
}
render() {
return (
<div className="App">
<img src={require("./images/frame.png")} alt="frame" id="instructFrame" />
<div className="resultsDiv">
<div className="targetNumber">
Target number = {this.state.targetNumber}
</div>
<div className="currentValue">
Current value = {this.state.currentValue}
</div>
<div className="gamesWon">
Games won = {this.state.gamesWon}
</div>
</div>
<div className="buttonGrid">
<Buttons
onClick={this.handleClick}
/>
</div>
</div>
);
}
}
export default App;
Buttons.js
import React, { Component } from "react";
import Button from "../Button/Button";
import black from "../Button/images/black_cat.png";
import brown from "../Button/images/brown_cat.png";
import gray from "../Button/images/gray_cat.png";
import yellow from "../Button/images/yellow_cat.png";
class Buttons extends Component {
generateNumber = (min, max) => {
const rndNumBtn = Math.floor(Math.random()*(max-min+1)+min);
console.log(rndNumBtn);
return rndNumBtn
};
state = {
buttons: [
{
id: "black",
src: black,
alt: "blackBtn",
value: this.generateNumber(1, 12)
},
{
id: "brown",
src: brown,
alt: "brownBtn",
value: this.generateNumber(1, 12)
},
{
id: "gray",
src: gray,
alt: "grayBtn",
value: this.generateNumber(1, 12)
},
{
id: "yellow",
src: yellow,
alt: "yellowBtn",
value: this.generateNumber(1, 12)
}
]
};
render() {
return (
<div>
{this.state.buttons.map(button => {
return (
<Button
className={button.id}
key={button.id}
src={button.src}
alt={button.alt}
value={button.value}
onClick={this.props.onClick.bind(this)}
/>
)
})}
</div>
)
}
}
export default Buttons;
Here's the GitHub repo. https://github.com/irene-rojas/numberguess-react
You can add a key to the Button component linking to the variable targetNumber. That way, React would rerender the Button whenever targetNumber changes.
<div className="buttonGrid">
<Buttons
key={this.state.targetNumber}
onClick={this.handleClick}
/>
</div>

ReactJS: how to map JSON elements sequentially and show the hidden div on click

I'm trying to load items from JSON and toggle a dropdown div with description on click. While I can display elements sequentially (ex: loc1 & desc1, loc2 & desc2) on static divs I'm having trouble finding out how to render it properly when the second part (desc) is hidden and only shows when the loc div is clicked.
What would be the best way to map the result so it doesn't show as loc1 & loc2, desc1 & desc2 but as loc1 & desc1, loc2 & desc2?
Code:
var places = {
library: {
location: [
{
loc_name: "library1",
"desc": "desc1 : Modern and spacious building"
},
{
loc_name: "library2",
"desc": "desc2 : A cosy small building"
}
]
}
};
function contentClass(isShow) {
if (isShow) {
return "content";
}
return "content invisible";
}
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { isShow: false };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(function (prevState) {
return { isShow: !prevState.isShow };
});
}
render() {
const libraries_desc = places.library.location.map((libr) =>
<div>
<p>{libr.desc}</p>
</div>
);
const lib_names = places.library.location.map((libr) =>
<div>
<p>{libr.loc_name}</p>
</div>
);
return (
<div>
<div className='control' onClick={this.handleClick}>
<h4>{lib_names}</h4>
<div className={contentClass(this.state.isShow)}>{libraries_desc}</div>
</div>
</div>
);
}
}
render((
<Toggle />
), document.getElementById('root'));
Current result:
library1
library2
desc1 : Modern and spacious building
desc 2 : A cosy small building
Desired Result:
library1
desc1 : Modern and spacious building (hidden but shown when clicked)
library2
desc 2 : A cosy small building (hidden but shown when clicked)
Codesandbox
I might try extracting a location into a separate component. By extracting it, each location is responsible for knowing its state. In your case, that means its visibility (controlled by this.state.isShow).
Here's how you could do it:
import React from 'react';
import { render } from 'react-dom';
var places = {
library: {
location: [
{
loc_name: "library1",
"desc": "Modern and spacious building"
},
{
loc_name: "library2",
"desc": "A cosy small building"
}
]
}
};
class Location extends React.Component {
constructor(props) {
super(props);
this.state = { isShow: false };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(function (prevState) {
return { isShow: !prevState.isShow };
});
}
contentClass(isShow) {
if (isShow) {
return "content";
}
return "content invisible";
}
render() {
return (
<div className='control' onClick={this.handleClick}>
<h4>{this.props.desc}</h4>
<div className={this.contentClass(this.state.isShow)}>{this.props.loc_name}</div>
</div>
)
}
}
class Toggle extends React.Component {
constructor(props) {
super(props);
}
render() {
const locations = places.library.location.map(location => {
return <Location {...location} />
})
return (
<div>
{locations}
</div>
);
}
}
render((
<Toggle />
), document.getElementById('root'));
Your Toggle Component should be like this.
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {
isShow: false,
id: -1, // initial value
};
}
handleClick = (id) => {
this.setState({
isShow: !this.state.isShow,
id: id
});
}
render() {
const { location } = places.library;
const { isShow, id } = this.state;
return (
<div className="control">
{location.map((libr, index) => (
<div key={index} onClick={() => { this.handleClick(index) }}>
<p>{libr.loc_name}</p>
{(isShow && (id === index)) && <p>{libr.desc}</p>}
</div>
))}
</div>
);
}
}
So when you click on the div element. A click event will be triggered called handleClick which will pass the index as a param to the function. which will set isShow to false or truth and vice versa along with the current element you want to show which will be selected through this.state.id. So everytime isShow is true and this.state.id matched index element of the array. Your description will show otherwise it will be hidden as you want.
So your desired result will be something like this.
library1
desc1 : Modern and spacious building (hidden but shown when clicked)
library2
desc 2 : A cosy small building (hidden but shown when clicked)

reactjs render array of objects into a list gives an error

so i create an object from a fetched json file and in showResult() function i add an object based on some conditions to an the array finalArray and i pass this array to the component Card and this should render a list, but it gives me an error items.map is not a function , but also if i change
finalArray: this.state.finalArray.push(new user(price, location, image, name, score))
to
finalArray: this.state.finalArray.concat(new user(price, location, image, name, score))
then it works but it only then shows the last object only showing only 1 list item which is not what i want, can someone help with pointing out the error or how to do this correctly since i am new to react and javascript
import React from 'react';
import Card from './Card.js';
export default class Slider extends React.Component {
constructor() {
super()
this.state = {
imgArray: [ "/img/work1.jpg", "/img/work2.jpg", "/img/work3.jpg"],
imgNo: 0,
url: "https://www.deskbookers.com/nl-nl/sajax.json?q=Amsterdam&type=-&people=any&favorite=0&pid=&sw=52.293753%2C4.634942&ne=52.455562%2C5.162286&ids=17201%2C19640%2C13692%2C13691%2C12136%2C17938%2C15292%2C14886%2C14885%2C14884%2C14883%2C15730%2C15353%2C15351%2C15330%2C15080%2C17290%2C15454%2C15451%2C15379",
current: "/img/work1.jpg",
search: '',
resultObject: null,
finalArray: [],
headlines: ["Pink Floyd Office", "Led Zeppelin Mania", "Central Perk Friends"],
headline : "Pink Floyd Office"
};
}
componentDidMount(){
this.serverRequest = $.get(this.state.url, function(result){
var info = result;
console.log(info);
this.setState({
resultObject:info
})
}.bind(this));
}
nextImg(){
if(this.state.imgNo < 2 && this.state.imgNo >=0 ){
this.setState({
imgNo : ++this.state.imgNo ,
current: this.state.imgArray[this.state.imgNo],
headline: this.state.headlines[this.state.imgNo]
})
}
}
prevImg(){
if(this.state.imgNo >= 1 && this.state.imgNo < 3 ){
this.setState({
imgNo : --this.state.imgNo,
current: this.state.imgArray[this.state.imgNo],
headline: this.state.headlines[this.state.imgNo]
})
}
}
searchQuery(e){
this.setState({
search: e.target.value
})
}
showResult(){
for(var i=0 ; i<this.state.resultObject.rows.length; i++){
if(this.state.search.toLowerCase() == this.state.resultObject.rows[i].location_city.toLowerCase()){
var price = this.state.resultObject.rows[i].day_price;
var location=(this.state.resultObject.rows[i].address[0]+", "+this.state.resultObject.rows[i].address[1]+", "+this.state.resultObject.rows[i].address[2]);
var image=this.state.resultObject.rows[i].image_urls2[0];
var name=this.state.resultObject.rows[i].location_name;
var score=this.state.resultObject.rows[i].location_rating;
if( price!=null && location!=null && image!=null && name!=null && score !=null){
function user(price, location, image, name, score){
this.price = price;
this.location = location;
this.image = image;
this.name = name;
this.score = score;
}
this.setState({
finalArray: this.state.finalArray.push(new user(price, location, image, name, score))
})
}
$(".card-list").show();
$('html,body').animate({
scrollTop: $(".card-list").offset().top},
'slow');
}
else{
$(".alert-box, .cancel").animate( { "opacity": "show", bottom:"0"} , 1250 );
$(".alert-box, .cancel").animate( { "opacity": "hide", bottom:"0"} , 3750 );
this.setState({
search: ""
})
$(".card-list").hide();
break;
}
}
}
render(){
return(
<div>
<div class="slider ">
<div class="img-container">
<img src={this.state.current} class="main-img" />
<div class="headline"><span>{this.state.headline}</span></div>
</div>
<img src="/img/slider-left.png" class="slider-arrow" onClick={this.prevImg.bind(this)} />
<img src="/img/slider-right.png" class="slider-arrow slider-right" onClick={this.nextImg.bind(this)} />
<div class="search-container">
<img src="/img/cancel.png" class="cancel hide"/>
<span class="alert-box hide">No offices available in this city, please try another one!</span>
<input onChange={this.searchQuery.bind(this)} value={this.state.search} type="text" name="search" placeholder="City name..." class="search-bar" />
<button disabled={!this.state.search} onClick={this.showResult.bind(this)} class="search-button">Sit me!</button>
</div>
</div>
<Card finalArray={this.state.finalArray}></Card>
</div>
);
}
}
import React from 'react';
export default class Card extends React.Component {
render(){
var items = this.props.finalArray;
var itemslist = items.map(function(item,index){
return(
<li key={index} class="card">
<img src={item.image} class="card-img" />
<div>
<div class="card-info">
<p class="workplace-name">{item.name}</p>
<span class="score">{item.score}</span>
<p class="location">{item.location}</p>
</div>
<div class="card-footer">
<p class="price">{item.price} €</p>
</div>
</div>
</li>
);})
return(
<ul class="card-list">
{ itemslist }
</ul>
);
}
}
The .push method returns the new length of the array. So when you do
this.setState({
finalArray: this.state.finalArray.push(...)
});
you are changing the value of this.state.finalArray from an array to a number. Of course numbers don't have a .map method.
If you want to add a new element to the array and create a new array, you can use .concat instead:
this.setState({
finalArray: this.state.finalArray.concat(...)
});
Overall your code appears to be more complicated than it has to be. E.g. the user function is unnecessary, just create the object directly. The null checks might also be unnecessary.
I'm not exactly sure how you expect your code to work, but to me it looks like the showResult results method should rather look like this:
showResults() {
var search = this.state.search.toLowerCase();
var finalArray = this.state.resultObject.rows
.filter(row => search == row.location_city.toLowerCase())
.map(row => ({
price: row.day_price,
location: rows.address.slice(0,3).join(', '),
image: row.image_urls2[0],
name: row.location_name,
score: row.location_rating,
}))
.filter(user => user.price != null &&
user.image != null &&
user.name != null &&
user.score != null
);
this.setState(
{
finalArray,
search: finalArray.length > 0 ? this.state.search : '',
},
() => {
// This is executed after the component updated
if (finalArray.length > 0) {
$(".card-list").show();
$('html,body').animate({
scrollTop: $(".card-list").offset().top
}, 'slow');
} else {
$(".alert-box, .cancel").animate( { "opacity": "show", bottom:"0"} , 1250 );
$(".alert-box, .cancel").animate( { "opacity": "hide", bottom:"0"} , 3750 );
$(".card-list").hide();
}
}
);
}
That is, create your data first, an array of objects and update the components state. After the update, check whether there are results or not show or hide the list based on that result. Note that manually changing the style of components is not something you'd usually do with React.

Categories