How map with function and text ReactJs - javascript

I would like to explain my problem of the day.
currently i map, everything works correctly
my problem and that I wish I could create a div in it in order to display the result of total
, unfortunately I can't
Do you have an idea of how to fix this?
{this.props.items.map(item => {
const product = this.props.items;
let total = 0;
console.log(total)
console.log('yolo',product)
console.log('yolo array',product[0].quantity)
for (let i = 0 ; i<product.length;i++){
console.log('products',product[i].quantity)
total = total + product[i].quantity;
}
}
)}

even if you were to render something using total, with this method you would render a "total item" for each item in props.items. What you want to use here is the reduce method. Here is an example with a very basic div, but you can decide what to render in place of it
<div>
{this.props.items.reduce((total,item) => item.quantity + total, 0)}
</div>
What the reduce methos does is returning a single value from a list of elements. The second parameter is your initial value, while he first is the callback that will be executed at each iteration

Related

Trying to build remove function, going wrong

I am trying to build a remove function to my weather app, the function working only on the last place in the array I tried via MAP loop but I get too many renders errors.
This is the sandbox URL of my project -
https://codesandbox.io/s/kind-platform-cymzx?fontsize=14&hidenavigation=1&theme=dark
I don't get it if ts working on the last one why won't you on the first one?
(with for loop it's letting me edit only the last one, in map loop, it's saying too many renders)
Guys I stuck on this for 3 days now please help.
Here is your function:
let deleteFunc = (name) => {
allFavorite.map((item, index) => {
console.log(item.name);
let updatedFavorite = allFavorite.filter((item, i) => (item.name = name));
setAllFavorite(updatedFavorite);
});
};
First problem is that you mutate item.name in filter function.
Second problem is that you are seting state inside the map, so you call setAllFavorite for each item in your allFavorite.
Your goal here is to construct new state first, and then apply it in one go, like this:
let deleteFunc = (name) => {
// this will return new array where item with name `name` removed, and will pass it into state setter
setAllFavorite(allFavorite.filter((item) => item.name !== name));
};

For loop a number to create buttons inside template literal

Getting a bit stuck with this one.
I'm looping through an object (dataLayer.Tests) and I'm displaying the values of my content, in a DIV. Here's an example of how this object looks:
I'm doing this by looping through my object with forEach. (And in this example, I'm just console.logging my result result3).
The problem I'm having, is that within my forEach, I want to display create/display buttons, depending on what the number is in the totalVariants key/value.
So for example, if the totalVariants === 2, I want to create 2 buttons. If it is one, I want to create 1 button.
I know I need to for loop through this particular value, but I'm not sure how to do this, within a template literal.
Here's my code.
dataLayer.Tests.forEach((element, index, array) => {
let result3 = '';
let numberOfVariants = element.totalVariants;
if (numberOfVariants >= 1) {
for (i = 0; i < numberOfVariants; i++) {
console.log("The number is ", i + 1);
}
result3 += `
<div class="CRO-variant-result">
<p>Date Launched: ${element.date}</p>
<p>Test ID: ${element.id}</p>
<p>Test Description: ${element.name}</p>
<p>Variant Active: ${element.variant}</p>
<p>Total Variants: ${element.totalVariants}</p>
${(function () {
for (i = 0; i < element.totalVariants; i++) {
return `<button>${i}</button>`
}
})()}
</div>
`
console.log("result3", result3);
};
});
I've seen solutions which include .map and object.keys, but this doesn't seem to work/return anything. (Probably as I just need to loop through a number and not array etc.
Any ideas/pointers, would be appreciated.
Basically, I'm not sure how to loop through a number, within a template literal and return x number of elements.
Thanks,
Reena
numberOfVariants is an number, not an object, so one way you could do this is create a new incrementing array of that length (Array.from(Array(numberOfVariants).keys()) does this nicely) and then map over that array as you're doing.
${Array.from(Array(numberOfVariants).keys()).map(i => (
`<button value="${i}">${i}</button>`
)).join('')}
I'm not quite sure what you want to appear inside the button (maybe the integer of the current number as you increment)?

Change style dynamically, without resetting when re-rendered in React

I have a page of just a list of divs calling an onClick function. Pretty much this...
<div
className="square card-container bg-primary"
points="200"
id="2"
onClick={e => select(200, "cat1", e.target.id)}
>
<h3 className="text-light">200</h3>
</div>
Just 30 of them. With sequential ID's. It's easy enough to push the ID's to a new array when clicked, or to add className once they're clicked, and when I step through the code in Debugger I can see that the class is Added and the styles change, but it is immediately set back to the previous "Un-clicked" className. I was thinking that it might work to make each of these div it's own component and than use useState, but since they're all mostly identical I would still need a key or id, so I'm not sure how I would pass that in to a state and use that conditionally? I'm sorry if this doesn't make sense. Basically I just want to change styles slightly once an item has been selected, without going back to the initial className when it is re-rendered.
This is the script that gets called onClick.
const selected = []
const change = id => {
selected.push(id);
console.log(selected);
};
const select = (points, cat, id) => {
let newArr = questions.filter(
q => q.category === "Sample 1" && q.points === points
);
change(id);
if (newArr.length > 1) {
let randomOutput = Math.floor(Math.random() * newArr.length);
console.log(newArr[randomOutput]);
let out = newArr[randomOutput];
props.setQuestion({ out });
props.detail();
return out;
} else {
let out = newArr;
props.setQuestion({ out });
props.detail();
console.log(points, cat);
}
}
You need to store a list of selected items using state and make className dynamic
Example: https://jsfiddle.net/78bsnhgw/

ReactJS: Page not being re-rendered on state change

I am learning react through the university of helsinki's full stack open course. The point of the code is there are two buttons and a quote shown on page. One button goes to a random quote and the other lets you put in a vote and shows how many votes that quote has total. The problem is that when I click vote, it adds the vote in the background but doesn't re-render the total amount of votes unless I change the quote.
I've tried different ways to go about conducting state change such as creating a function specifically for the setVote but I can't get it to work.
const App = () => {
const [selected, setSelected] = useState(0)
let [vote, setVote] = useState([...copyVote])
const changeAnecdote = () => {
setSelected(Math.floor(Math.random() * 6))
}
const addVote = () => {
copyVote[selected] = copyVote[selected] + 1
setVote(vote = copyVote)
}
return (
<div>
<Button onClick={changeAnecdote} text='Next Anecdote'/>
<Button onClick={addVote} text='Vote'/>
<div>
{anecdotes[selected]}
<DisplayVotes vote={vote} selected={selected}/>
</div>
</div>
)
}
copyVote is a copy of a zero-filled array and DisplayVotes simply shows how many votes total for that quote on screen.
When I check for changes in the array of votes after hitting vote through developer tools, the array doesn't change until I go to another quote.
Anyone have any ideas as to what I'm doing wrong?
There is a few things that should be updated here.
Firstly, copyVote is an array containing the number of votes for each quote. So ...copyVote will give you each item in that array. You only want the vote for the current quote. Your initial vote state should be
const [vote, setVote] = useState(copyVote[selected])
You also want to update the addVote function the way DSCH mentioned.
const addVote = () => {
// copyVote[selected]++ is the same as copyVote[selected] += 1 and copyVote[selected] = copyVote[selected] + 1
setVote(copyVote[selected]++)
}
Finally, you want to add a way to update the vote each time the anecdote is changed. You could do this in the changeAnecdote function, but a better approach would be to use an effect hook that is dependent on the selected state.
useEffect(() => {
// Set the value of vote to match the newly selected quote
setVote(copyVote[selected])
}, [selected])
Using this, the DisplayVotes vote prop is only going to display the vote for the currently selected quote. You may need to updated that component to handle this.
In setVote(vote = copyVote) the expression within the parentheses is an expression to set the vote variable with the value in copyVote. I assume that's why you use let in let [vote, setVote] = useState([...copyVote]), since probably you got an error setting a value to a const.
As setVote is what return from the useState what you probably want to do is:
const addVote = () => {
copyVote[selected] = copyVote[selected] + 1
setVote(copyVote[selected])
}

slice happens in the code but it doesnt update in the UI

there are three drop down menus in the initial state.
after I select the first drop down the second drop down values gets loaded
after I select the second drop down values.
a new set of drop down loads.
when I select remove button of the second set.
it doesnt remove that set but it removes the first set.
when I debugged removeSelectedValue method there slices are happening correctly but its not updating in the updating
can you tell me how to pass the queryComponents values so that it will update in the UI.
can you tell me how to fix it.
so that in future I will fix it myself.
providing my relevant code snippet and sandbox below.
all my code is in demo.js
https://codesandbox.io/s/4x9lw9qrmx
removeSelectedValue = index => {
console.log("removeSelectedValue--->", index);
let seletedValues = this.state.queryComponents;
seletedValues.splice(index, 1);
console.log("spliced Values--->", seletedValues);
this.setState({ queryComponents: seletedValues });
};
render() {
let queryComp = this.state.queryComponents.map((value, index) => {
return (
<AutoCompleteComponent
key={index}
value={value}
index={index}
valueSelected={this.getSelectedValue}
removeSeleted={this.removeSelectedValue}
/>
);
});
return <div>{queryComp}</div>;
}
When you do let seletedValues = this.state.queryComponents;
you're creating a reference to that variable, instead of making a copy.
You need to make sure you replace your state with a new object/array for the re-render to happen.
Please try this:
removeSelectedValue = index => {
this.setState(prevState => ({
queryComponents: prevState.seletedValues.filter((a, i) => (i !== index));
});
};
That filter function is equivalent to the splice you were using, but returns a new array instead of modifying the original one.
On the other hand, I 'm passing setState a function that uses prevState making the code shorter.

Categories

Resources