so im new to react and there is a book and a task given i need to filter out users by the upvotes the one user with most upvotes must be on the top but i have no idea how to do it also when i press on one user the state of upvote changes on all users can anyone help ? what am i doing wrong or am i doing everything wrong
import React from 'react';
import Nav from './Nav';
import './App.css';
import react,{Component} from'react'
const Items = [
{
img: "https://pbs.twimg.com/profile_images/1219033860991848448/UKWAPwfG_400x400.jpg",
header:"Netlify, our Conversion from Angular to React",
website:"netlify.com",
timeAuthor:"Submitted 9 hours ago by brianlammar",
},
{
img:"https://pbs.twimg.com/profile_images/1825094360/random_dude_400x400.jpg",
header:"React in patterns - List of design patterns ragaca",
website:"github.com",
timeAuthor:"Submitted 9 hours ago by magenta_placenta",
},
{
img:"https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/c8366146-25b7-49b3-a640-58439d2a2baa/d5gs9sv-0c98ab64-0f32-4c6d-90ed-39d38d2bf0ba.jpg/v1/fill/w_900,h_675,q_75,strp/random_dude_who_lives_near_me_by_misa_amane_17_d5gs9sv-fullview.jpg?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOjdlMGQxODg5ODIyNjQzNzNhNWYwZDQxNWVhMGQyNmUwIiwiaXNzIjoidXJuOmFwcDo3ZTBkMTg4OTgyMjY0MzczYTVmMGQ0MTVlYTBkMjZlMCIsIm9iaiI6W1t7ImhlaWdodCI6Ijw9Njc1IiwicGF0aCI6IlwvZlwvYzgzNjYxNDYtMjViNy00OWIzLWE2NDAtNTg0MzlkMmEyYmFhXC9kNWdzOXN2LTBjOThhYjY0LTBmMzItNGM2ZC05MGVkLTM5ZDM4ZDJiZjBiYS5qcGciLCJ3aWR0aCI6Ijw9OTAwIn1dXSwiYXVkIjpbInVybjpzZXJ2aWNlOmltYWdlLm9wZXJhdGlvbnMiXX0.YP5o5wapk-q4-6vpQIKaERchdyvNl8MOAs_cbG7ThfU",
header:"Redux vs Mobx vs Flux vs... Do you even...",
website:"goshakkk.name",
timeAuthor:"Submitted 8 hours ago by goshakk",
}
]
class App extends Component{
constructor(props){
super(props)
this.state= {
count:0
}
}
incremento(){
this.setState({
count:this.state.count + 1
})
}
decremento(){
this.setState({
count:this.state.count -1
})
}
render(){
return (
Items.map(item =>{
return (
<div>
<div className='section'>
<span className='Votes'>
<i onClick={() => this.incremento()} className="fas fa-arrow-up"></i>
<p>{this.state.count}</p>
<i onClick={() => this.decremento()} className="fas fa-arrow-down"></i>
</span>
<img src={item.img} />
<div className='Content'>
<h1 className='h'>{item.header}</h1>
<p>{item.website}</p>
<p>{item.timeAuthor}</p>
<span className='lil'>
<p className='red'>10 Comments</p>
<p>share</p>
<p>save</p>
<p>hide</p>
<p>report</p>
<p>pocket</p>
</span>
</div>
</div>
</div>
)
})
)
}
}
export default App;
It should look like this:
https://codesandbox.io/s/gracious-glitter-jw34l?file=/src/App.js
import React { useState } from "react";
import Nav from './Nav';
import './App.css';
const Items = [
{
id: 1,
count: 0,
img:
"https://pbs.twimg.com/profile_images/1219033860991848448/UKWAPwfG_400x400.jpg",
header: "Netlify, our Conversion from Angular to React",
website: "netlify.com",
timeAuthor: "Submitted 9 hours ago by brianlammar"
},
{
id: 2,
count: 0,
img:
"https://pbs.twimg.com/profile_images/1825094360/random_dude_400x400.jpg",
header: "React in patterns - List of design patterns ragaca",
website: "github.com",
timeAuthor: "Submitted 9 hours ago by magenta_placenta"
},
{
id: 3,
count: 0,
img:
"https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/c8366146-25b7-49b3-a640-58439d2a2baa/d5gs9sv-0c98ab64-0f32-4c6d-90ed-39d38d2bf0ba.jpg/v1/fill/w_900,h_675,q_75,strp/random_dude_who_lives_near_me_by_misa_amane_17_d5gs9sv-fullview.jpg?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOjdlMGQxODg5ODIyNjQzNzNhNWYwZDQxNWVhMGQyNmUwIiwiaXNzIjoidXJuOmFwcDo3ZTBkMTg4OTgyMjY0MzczYTVmMGQ0MTVlYTBkMjZlMCIsIm9iaiI6W1t7ImhlaWdodCI6Ijw9Njc1IiwicGF0aCI6IlwvZlwvYzgzNjYxNDYtMjViNy00OWIzLWE2NDAtNTg0MzlkMmEyYmFhXC9kNWdzOXN2LTBjOThhYjY0LTBmMzItNGM2ZC05MGVkLTM5ZDM4ZDJiZjBiYS5qcGciLCJ3aWR0aCI6Ijw9OTAwIn1dXSwiYXVkIjpbInVybjpzZXJ2aWNlOmltYWdlLm9wZXJhdGlvbnMiXX0.YP5o5wapk-q4-6vpQIKaERchdyvNl8MOAs_cbG7ThfU",
header: "Redux vs Mobx vs Flux vs... Do you even...",
website: "goshakkk.name",
timeAuthor: "Submitted 8 hours ago by goshakk"
}
],
User = ({ counterChange, item }) => (
<div>
<div className="section">
<span className="Votes">
<i
onClick={() => {
counterChange(1);
}}
className="fas fa-arrow-up"
>
UP
</i>
<p>{item.count}</p>
<i
onClick={() => {
counterChange(-1);
}}
className="fas fa-arrow-down"
>
DOWN
</i>
</span>
<img src={item.img} />
<div className="Content">
<h1 className="h">{item.header}</h1>
<p>{item.website}</p>
<p>{item.timeAuthor}</p>
<span className="lil">
<p className="red">10 Comments</p>
</span>
</div>
</div>
</div>
);
const App = () => {
const [items, setItems] = useState(Items);
return (
<>
{items
.sort((a, b) => (a.count < b.count ? 1 : -1))
.map((item) => (
<User
item={item}
counterChange={(value) => {
const index = items.findIndex((d) => d.id === item.id),
a = [...items];
a[index].count = a[index].count + value;
setItems(a);
}}
/>
))}
;
</>
);
};
export default App;
The count is increasing for each user because, the count state that you are maintaining is not specific to a user. It is a general, common counter.
What you could instead do is,
Get rid of the count state.
Add a users state, which will be an array of users, with a count for each user. Something like:
this.state = Items.map(i => ({...i, count: 0}))
Pass an id to the incremento(id) and decremento(id) methods.
This way now, you can update the count of only the user for which the up/down button was clicked inside your incremento() and decremento() methods
And in the render method, you can sort the Items array by the count field, and then render each user.
This way, you can have the count increased only for the clicked user, and users sorted by counts in descending order.
Related
In typescript code I tried to disable the "-" button in the Shopping Cart if amount of item = 1.
Currently, when clicking the "-" button we can reach amount 0, -1, -2 etc. I tried to disable it using jQuery and JS code, but in result received only mistake.
Could you please help with answer how to make it work properly?
import {
CardContent,
CardActions,
Button,
Card,
TextField,
} from '#mui/material'
import { Component } from 'react'
import './ProductListItem.scss'
type Props = {
title: string
description: string
type: string
capacity: string
price: number
image: string
}
type State = {
count: number
}
class ProductListItem extends Component<Props, State> {
constructor(props: Props) {
super(props)
this.state = {
count: 1,
}
this.onIncrementClick = this.onIncrementClick.bind(this)
this.onDecrementClick = this.onDecrementClick.bind(this)
}
onIncrementClick() {
this.setState((prevState) => ({
count: prevState.count + 1,
}))
}
onDecrementClick() {
this.setState((prevState) => ({
count: prevState.count - 1,
}))
}
render() {
const { title, description, type, capacity, price, image } = this.props
return (
<Card variant="outlined" className="product">
<CardContent>
<div className="product-image">
<img src={image} alt="" />
</div>
<div className="product-title">{title}</div>
<div className="product-description">{description}</div>
<div className="product-features">Type:{type}</div>
<div className="product-features">Capacity:{capacity}</div>
<div className="product-price">Price:{price}</div>
<div className="product-quantity">
<Button
variant="outlined"
onClick={this.onDecrementClick}
>
-
</Button>
<TextField size="small" value={this.state.count} />
<Button
variant="outlined"
onClick={this.onIncrementClick}
>
+
</Button>
</div>
</CardContent>
<CardActions className="btns-wrap">
<Button variant="outlined">Add to cart</Button>
</CardActions>
</Card>
)
}
}
export default ProductListItem
Expacting to receive result like code below, but in TS
let input = document.querySelector(".input");
let button = document.querySelector(".button");
button.disabled = true;
input.addEventListener("change", stateHandle);
function stateHandle() {
if (document.querySelector(".input").value === "") {
button.disabled = true;
} else {
button.disabled = false;
}
}
No need to add event listeners and such. You can do this by using the disabled prop as written on the MUI Button props documentation and passing the count state as a check.
<Button
variant="outlined"
onClick={this.onDecrementClick}
disabled={this.state.count === 1}
>
-
</Button>
I am having a problem changing the text color based on either the element has negative value or positive one.
I have an array with data, containing negative/positive values of each user's balance (fake data ofc).
data.js
export const users = [
{
id: 0,
username: "CryptoFunks",
emailAddress: "example#gmail.com",
balanceRate: +26.52,
balance: "19,769.39",
avatar: cryptoFunksAvatar,
verified: true,
},
{
id: 1,
username: "Cryptix",
emailAddress: "example#gmail.com",
balanceRate: -10.52,
balance: "2,769.39",
avatar: cryptixAvatar,
verified: false,
},
{
id: 2,
username: "Frensware",
emailAddress: "example#gmail.com",
balanceRate: +2.52,
balance: "9,232.39",
avatar: frenswareAvatar,
verified: false,
},
{
id: 3,
username: "PunkArt",
emailAddress: "example#gmail.com",
balanceRate: +1.52,
balance: "3,769.39",
avatar: punkArtAvatar,
verified: true,
},
{
id: 4,
username: "Art Crypto",
emailAddress: "example#gmail.com",
balanceRate: -2.52,
balance: "10,769.39",
avatar: artCryptoAvatar,
verified: false,
},
];
And here's what I am trying to do with it.
TopCollections.jsx
import React, { useEffect, useState } from "react";
import { users } from "../../public/data/data";
const TopCollections = () => {
const [isNegative, setIsNegative] = useState(false);
useEffect(() => {
users.forEach((element) => {
if (element.balanceRate < 0) {
setIsNegative(true);
} else if (element.balanceRate > 0) {
setIsNegative(false);
}
});
});
return (
<section>
<div className="container max-w-[1216px] mx-auto px-4">
<div>
<h3>Top collections over</h3>
<p>Last 7 days</p>
<ul>
{users.map((item, index) => {
return (
// item
<li key={index}>
{/* index */}
<span>{index + 1}</span>
{/* avatar */}
<img src={item.avatar} />
{/* username & balance */}
<div>
<p>{item.username}</p>
<p>{item.balance}</p>
</div>
{/* balance rate */}
<span
className={`${
isNegative ? "text-[#FF002E]" : "text-[#14C8B0]"
}`}
>
{item.balanceRate}%
</span>
</li>
);
})}
</ul>
</div>
</div>
</section>
);
};
export default TopCollections;
Implementation is awful, sorry for that, I am pretty new to this, however I was trying to figure out how to determine whether the value is negative or positive. I tried to do forEach() function for each element of the array and it seems to be working fine if I check with console.log(); it actually defines numbers with negative & positive values. The main problem is that it does not change color based on state, that I specified. I feel like there is a dumb newbie issue which I do not see point blank, but still.
You don't need a state here. isNegative is a (computable) property of each user user.balanceRate < 0 and it's so simple to compute that you don't need to store it anywhere.
const TopCollections = () => {
return (
<section>
<div className="container max-w-[1216px] mx-auto px-4">
<div>
<h3>Top collections over</h3>
<p>Last 7 days</p>
<ul>
{users.map((item, index) => {
return (
// item
<li key={item.id}>
{/* index */}
<span>{index + 1}</span>
{/* avatar */}
<img src={item.avatar} />
{/* username & balance */}
<div>
<p>{item.username}</p>
<p>{item.balance}</p>
</div>
{/* balance rate */}
<span
className={
item.balanceRate<0 ? "text-[#FF002E]" : "text-[#14C8B0]"
}
>
{item.balanceRate}%
</span>
</li>
);
})}
</ul>
</div>
</div>
</section>
);
};
there a couple of problems with the code you shared.
I think you misunderstand how useState and useEffect work and how they are used. Also, in the future I would say to you should avoid using forEach at all costs as you will mutate your data and that can cause problems that are hard to debug down the road.
To be honest I don't think you need either hooks to solve your problem, you already have all the data you need in the users array. You just need to define the Boolean in the map statement you already have in your code. So you can remove those hooks and just add the following const to your map statement to figure out which user has a negative balance:
{users.map((item, index) => {
const isNegative = item.balanceRate < 0;
return (
...
)
You don't need to use useState hook and useEffect hook as well, there are couple of mistakes you did. You have set isNavigate "true" for all elements of user array.
import React, { useEffect, useState } from "react";
import { users } from "../../public/data/data";
const TopCollections = () => {
return (
<section>
<div className="container max-w-[1216px] mx-auto px-4">
<div>
<h3>Top collections over</h3>
<p>Last 7 days</p>
<ul>
{users.map((item, index) => {
return (
// item
<li key={index}>
{/* index */}
<span>{index + 1}</span>
{/* avatar */}
<img src={item.avatar} />
{/* username & balance */}
<div>
<p>{item.username}</p>
<p>{item.balance}</p>
</div>
{/* balance rate */}
<span
className={`${
item.balanceRate > 0 ? "text-[#14C8B0]" :
"text-[#FF002E]"
}`}
>
{item.balanceRate}%
</span>
</li>
);
})}
</ul>
</div>
</div>
</section>
);
};
export default TopCollections;
So I've been struggling for a while with retrieving data from APIs and or retrieving local json files. I am using React axios but even with the normal fetch method I am having the same issues. When I fetch the endpoint and save the code, my jsx refreshes and the data appears on the screen but then when I refresh the page, it's no longer there and doesn't appear when I refresh again and again. I have no idea what I am doing wrong. I tried to retrieve the data on the parent and set it as props but still the same problem.
My child component:
import React, { useEffect, useState } from 'react';
import './Card.scss';
import axios from 'axios';
import { ellipsisIcon } from '../../constants/images';
import dataJson from './data.json';
const Card = ({ name, color, icon, currentTime }) => {
const [data, setData] = useState([]);
const [daily, setDaily] = useState([]);
const [weekly, setWeekly] = useState([]);
const [monthly, setMonthly] = useState([]);
useEffect(() => {
const fetchData = async () => {
const result = await axios.get('data.json');
setData(result.data);
setData(
data.filter((item) => {
return item.title === name;
}),
);
setDaily(data[0].timeframes.daily);
setWeekly(data[0].timeframes.weekly);
setMonthly(data[0].timeframes.monthly);
};
fetchData();
}, []);
return (
<div className="card" style={{ backgroundColor: `${color}` }}>
<img src={icon} alt={`${name} icon`} />
<div className="card__container bg-blue">
<div className="card__top-container flex">
<p className="text-white ">{name}</p>
<div className="card__top__elipse-container">
<img src={ellipsisIcon} alt="ellipsis" />
</div>
</div>
<div className="card__bottom-container">
{currentTime === 0 && (
<>
<h1 className="fs-900 text-white">{daily.current}hrs</h1>
<div className="card__bottom__prev-container">
<p className="text-accent ">
Yesterday -<span>{daily.previous}hrs</span>
</p>
</div>
</>
)}
{currentTime === 1 && (
<>
<h1 className="fs-900 text-white">{weekly.current}hrs</h1>
<div className="card__bottom__prev-container">
<p className="text-accent ">
Last Week -<span>{weekly.previous}hrs</span>
</p>
</div>
</>
)}
{currentTime === 2 && (
<>
<h1 className="fs-900 text-white">{monthly.current}hrs</h1>
<div className="card__bottom__prev-container">
<p className="text-accent">
Last Month -<span>{monthly.previous}hrs</span>
</p>
</div>
</>
)}
</div>
</div>
</div>
);
};
export default Card;
My App (Parent):
import { useState, useEffect } from 'react';
import Card from './components/Card/Card';
import {
pbImage,
ellipsisIcon,
exerciseIcon,
playIcon,
careIcon,
socialIcon,
studyIcon,
workIcon,
} from './constants/images';
const cards = [
{
name: 'Exercise',
color: 'hsl(var(--clr-exercise))',
icon: exerciseIcon,
},
{
name: 'Play',
color: 'hsl(var(--clr-play))',
icon: playIcon,
},
{
name: 'Self Care',
color: 'hsl(var(--clr-care))',
icon: careIcon,
},
{
name: 'Social',
color: 'hsl(var(--clr-social))',
icon: socialIcon,
},
{
name: 'Study',
color: 'hsl(var(--clr-study))',
icon: studyIcon,
},
{
name: 'Work',
color: 'hsl(var(--clr-work))',
icon: workIcon,
},
];
function App() {
const [selectedTime, setSelectedTime] = useState(2);
return (
<div className="app bg-dark">
<div className="main__container grid">
<div className="side__card-container">
<div className="side__card__top flex">
<div className="side__card__top__pb-container">
<img
src={pbImage}
alt="pb"
className="side__card__top__pb-image pb-image"
/>
</div>
<div className="side__card__top__person-container">
<p className="fs-600 text-accent">Report for</p>
<h2 className="fs-800 text-white">Jeremy Robson</h2>
</div>
</div>
<div className="side__card__bottom">
<div>Daily</div>
<div>Weekly</div>
<div>Monthly</div>
</div>
</div>
{cards.map((card, _index) => (
<Card
key={_index}
name={card.name}
color={card.color}
icon={card.icon}
currentTime={selectedTime}
/>
))}
</div>
</div>
);
}
export default App;
As I mentioned in the comments, states are updated asynchronously. So, you should be careful when you use a state immediately after setting its value. In your case, you shouldn’t use the data state because you are not sure that it has a value. Try changing to this.
useEffect(() => {
const fetchData = async () => {
const result = await axios.get('data.json');
const filteredData = result.data.filter((item) => {
return item.title === name;
})
setData(filteredData);
// make sure result data isn’t empty
setDaily(result.data[0].timeframes.daily);
setWeekly(result.data[0].timeframes.weekly);
setMonthly(result.data[0].timeframes.monthly);
};
fetchData();
}, []); // "[]" makes the useEffect callback only run after the first render
I'm creating a simple recipe app that uses edamam's API. The data returned from edamam doesn't have a unique ID for each recipe element. As a result, I'm trying to use UUID to create unique Ids for all recipes that are returned. However, neither of the solutions that I'm applying creates a unique id.
My Recipe Component
import React, {useState, useEffect} from 'react';
import Recipe_Tiles from './Recipe_Tiles'
import { API_ID, API_KEY} from '../../Config'
import uuid from 'uuid/v4'
import '../../App.css'
function Recipe() {
//Initialized states
const [Search, setSearch] = useState("");
const [Term, setTerm] = useState();
const [Recipe, setRecipe] = useState([]);
let id = uuid();
//useEffect will run again if the Term state is updated
useEffect(() => {
getAPI();
}, [Term]);
//method to retrieve recipes
const getAPI = () => {
fetch(`https://api.edamam.com/search?q=${Term}&app_id=${API_ID}&app_key=${API_KEY}`)
.then(response => response.json())
.then(response => {
console.log(response)
setRecipe(response.hits)
})
}
const handleChange = (e) => {
setSearch(e.target.value);
}
const handleSubmit = (e) => {
e.preventDefault();
setTerm(Search);
setSearch("");
}
return (
<div
className="App"
style = {{marginLeft: "15px"}}
>
<h1 style = {{textAlign: 'center'}}>The Recipe App</h1>
<form onSubmit = {handleSubmit}>
<div className="row inputs">
<div className="input-field col s6">
<label htmlFor="first_name"> Search for Recipes</label>
<input
className = "recipe-input"
type = "text"
value = {Search}
onChange = {handleChange}
/>
</div>
<button
className="btn waves-effect waves-light button-input"
type="submit"
onSubmit = {handleSubmit}
name="action">Search
<i className="material-icons right">local_dining</i>
</button>
</div>
</form>
{/*
The recipe tiles component is used to create the recipe cards.
Once data is retrieved from the API, it'll be passed as props to the component.
*/}
{Recipe.map(i => (
<Recipe_Tiles
title = {i.recipe.label}
calories = {i.recipe.calories}
image = {i.recipe.image}
URL = {i.recipe.url}
ingredients = {i.recipe.ingredients}
id = {id}
/>
))}
</div>
);
}
export default Recipe;
My Recipe_Tiles Component:
import React from 'react'
export default function Recipe_Tiles ({title, calories, image, URL,ingredients, id}) {
return(
<div class="card">
<div class="card-image waves-effect waves-block waves-light">
<img class="activator" src={image} alt = "this is a recipe"/>
</div>
<div class="card-content">
<span class="card-title activator grey-text text-darken-4"
style = {{fontSize: '15px',lineHeight:'20px', fontWeight: '700'}}>{title}
<i class="material-icons right">more_vert</i>
</span>
<br />
<hr style = {{width: '40%', marginLeft: '90px', marginBottom: '10px'}}/>
<p> Calories: {Math.floor(calories)} | Ingredients: {ingredients.length}</p>
<br />
<p><a href={URL}>View The Complete Recipe Here</a></p>
</div>
<div class="card-reveal">
<span
class="card-title grey-text text-darken-4"
style = {{fontSize: '15px', lineHeight:'20px', fontWeight: '700', marginRight: '20px',marginTop: '50px'}}>
Ingredients List:<i class="material-icons right">close</i></span>
<ol>
{ingredients.map(i => (
<li style = {{marginLeft: '-40px'}}>{i.text}</li>
))}
</ol>
<p>My id is {id}</p>
</div>
</div>
)
}
Solution attempt 1:
In my Recipe component,create a variable called id and set it to UUID(). Next, pass this variable as a props in my map function. The problem with this solution is that it creates a UUID that is the same for all recipes.
Solution attempt 2
In my Recipe component and in my map function, create a prop called Id and pass it this: i.uuid(). However, I receive a Unhandled Rejection (TypeError): i.uuid is not a function error.
Here is the data returned from Edamam's API:
q: "chicken",
from: 0,
to: 10,
more: true,
count: 168106,
hits: [
{
recipe: {
uri: "http://www.edamam.com/ontologies/edamam.owl#recipe_b79327d05b8e5b838ad6cfd9576b30b6",
label: "Chicken Vesuvio",
image: "https://www.edamam.com/web-img/e42/e42f9119813e890af34c259785ae1cfb.jpg",
source: "Serious Eats",
url: "http://www.seriouseats.com/recipes/2011/12/chicken-vesuvio-recipe.html",
shareAs: "http://www.edamam.com/recipe/chicken-vesuvio-b79327d05b8e5b838ad6cfd9576b30b6/chicken",
yield: 4,
dietLabels: [],
healthLabels: [],
cautions: [],
ingredientLines: [],
ingredients: [],
calories: 4055.7632762010808,
totalWeight: 2765.5901364771207,
totalTime: 60,
totalNutrients: {},
totalDaily: {},
digest: []
},
bookmarked: false,
bought: false
},
{
recipe: {
uri: "http://www.edamam.com/ontologies/edamam.owl#recipe_8275bb28647abcedef0baaf2dcf34f8b",
label: "Chicken Paprikash",
image: "https://www.edamam.com/web-img/e12/e12b8c5581226d7639168f41d126f2ff.jpg",
source: "No Recipes",
url: "http://norecipes.com/recipe/chicken-paprikash/",
shareAs: "http://www.edamam.com/recipe/chicken-paprikash-8275bb28647abcedef0baaf2dcf34f8b/chicken",
yield: 4,
dietLabels: [],
healthLabels: [],
cautions: [],
ingredientLines: [],
ingredients: [],
calories: 3033.2012500008163,
totalWeight: 1824.6125000003276,
totalTime: 0,
totalNutrients: {},
totalDaily: {},
digest: []
},
bookmarked: false,
bought: false
},
Any suggestions or feedback would be much appreciated!
I was also faced to this issue concerning how to get the recipe ID. Finally, I found a solution, maybe this will help you.
First of all, each recipe has an unique 'uri' from Edamam API. Inside the uri, you will be able to find the recipe-ID (after the '#recipe_).
So, you could try to extract the ID from the uri string by using a small function like that :
extractIdFromUri(uri) {
return uri.split('#recipe_').pop()
}
It's worked for me.
Update the hits array using map() to return a new array with the uniqueId as an additional key. This can be achieved using ES6 spread syntax
const updatedHits = response.hits.map((recipe) => {
uniqueId: uuid(),
...recipe
});
setRecipe(updatedHits);
I have this "trash" button:
<button
type='reset'
className='c-btn--ghost no-border'
onClick={(e) => this.props.handleProjectDelete(e, project.id)}>
<i className='fa fa-trash u-margin-right-tiny'/>
</button>
This is the page with the button.
And when I click it I want a component called CustomModal to render with this props:
<CustomModal
alternateModalClass='c-group-stickies-modal'
onClosePress={this.handleCloseClick}
alternateCloseButtonClass='c-group-stickies-modal__close-button'
text={'are you sure you want to delete it?'}
/>
So a modal like this can appear:
But I don't know how to do that.
This is the component that has the trash button:
https://jsfiddle.net/10u6pfjp/
And this is the CustomModal component: https://jsfiddle.net/cp29ms8g/
As others have mentioned, you should be approaching this with a conditional statement as to whether or not your modal should appear by having a variable in this.state. Change it in your button onClick. Since you now have 2 functions to run, I made a new function called handleProjectDelete in your component to handle both at once.
At the bottom of your render, you'll see that I added the conditional where you should place a modal. I used <Modal/> as a placeholder. Use CSS to force it into a position that's appropriate for a modal.
const MAX_PROJECTS_PER_PAGE = 10
export class ProjectsTable extends Component {
constructor() {
super()
this.state = {
showModal: false
}
}
componentWillReceiveProps(nextProps) {
const { history, organizations, hasFetched } = nextProps
if (!deepEqual(this.props, nextProps) && hasFetched) {
if (!organizations || organizations.isEmpty()) {
history.push('/beta-code')
}
}
}
handleProjectDelete(e, project.id) {
this.setState({showModal: true})
this.props.handleProjectDelete(e, project.id)
}
renderProjectsTable() {
const { projects } = this.props
const projectsWithoutDefault = projects.filter(proj => proj.name !== 'default')
const projectsTable = projectsWithoutDefault.map((project) => {
return ({
name: <NavLink to={`/projects/${project.id}`}> {project.name} </NavLink>,
team: <UsersList users={fromJS(project.users)} showBadge showMax={5} type='list' />,
retro:
(project.lastRetro)
? <NavLink className='c-nav-link'
exact to={`/retrospectives/${project.lastRetro.id}`}>
{moment.utc(project.lastRetro.date)
.format('dddd, DD MMMM YYYY').toString()}
</NavLink> : <div>No retros found</div>,
delete:
<div className='delete-align'>
<button
type='reset'
className='c-btn--ghost no-border'
onClick={(e) => this.handleProjectDelete(e, project.id)}>
<i className='fa fa-trash u-margin-right-tiny'/>
</button>
</div>
})
})
return projectsTable
}
render () {
return (
<div className='o-wrapper u-margin-top'>
<TablePagination
title='Projects'
data={ this.renderProjectsTable()}
headers={['Name', 'Team', 'Last Retrospective', ' ']}
columns='name.team.retro.delete'
nextPageText='>'
prePageText='<'
perPageItemCount={ MAX_PROJECTS_PER_PAGE }
totalCount={ this.renderProjectsTable().length }
arrayOption={ [['size', 'all', ' ']] }
/>
{ this.state.showModal ? <div className='delete-modal'><Modal/><div/> : null }
</div>
)
}
}
const mapStateToProps = ({
projects
}) => ({
hasFetched: projects.get('hasFetched'),
projects: projects.get('projects')
})
ProjectsTable.defaultProps = {
projects: []
}
export default connect(mapStateToProps)(ProjectsTable)
I hope you can do this as below
<button
type='reset'
className='c-btn--ghost no-border'
onClick={(e) => {
this.props.handleProjectDelete(e, project.id);
this.renderModal;
}}>
<i className='fa fa-trash u-margin-right-tiny'/>
</button>