Explain item.id === id ? { ...item, checked: !item.checked } : item - reactjs

const listItems = items.map((item) =>
item.id === id ? { ...item, checked: !item.checked } : item
)
Especially what is the difference between item.id and id? and why use : item at the end?
Full code below, Note that the code isn't something I'm working on, it is a tutorial and there is still more to code
import React from "react";
import { useState } from "react";
import { FaTrashAlt } from "react-icons/fa";
const Content = () => {
const [items, setItems] = useState([
{
id: 1,
checked: false,
item: "One half bag of cocoa covered",
},
{
id: 2,
checked: false,
item: "Item 2",
},
{
id: 3,
checked: false,
item: "Item 3",
},
]);
const handleCheck = (id) => {
console.log(`key: ${id}`);
const listItems = items.map((item) =>
item.id === id ? { ...item, checked: !item.checked } : item
);
setItems(listItems);
localStorage.setItem("shoppinglist", JSON.stringify(listItems));
};
return (
<main>
<main>
<ul>
{items.map((item) => (
<li className="item" key={item.id}>
<input
type="checkbox"
onChange={() => handleCheck(item.id)}
checked={item.checked}
/>
<label
style={item.checked ? { color: "red" } : { color: "green" }}
onClick={() => handleCheck(item.id)}
>
{item.item}
</label>
{/* <button>Delete</button> */}
<FaTrashAlt
onClick={() => handleCheck(item.id)}
role="button"
tabIndex="0"
/>
</li>
))}
</ul>
</main>
</main>
);
};
export default Content;

items.map(item => ) is mapping over an array of items, item is the object of the current item being mapped
id is the id that comes from handleCheck function(triggered onClick), which is the id of the clicked item, while item.id is the id of the current item from the array of objects
item.id === id ? { ...item, checked: !item.checked } : item uses the ternary operator which is a shorthand if/else to check if the id of the current item is the same as the id of the clicked item
if it is(true) it adds to the current item object checked: !item.checked, if it isn't(false) it returns the item object as it is

Here this code trying to keep items array immutable,if you change item.checked value it without using
It will modify items array too
{ ...item, checked: !item.checked }
And Id is used to collect only particular item and modifications of it.

The map function iterates through all the items in a list. Each item has an id, which is the list.id variable. The function takes id as a param.
Then if item.id equals the passed in id, a modified item will be returned. If not, the iten is returned unmodified. That's what :item at the end is for.

A few basics to start since I'm not sure where the confusion lies:
map() takes the contents of a list and returns another list / array
based on those concepts. e.g. [1,2,3].map(x => x *2) will return [ 2, 4, 6 ]
The ternary ?: operator takes three args (hence the name) If the
first is true, returns the second, otherwise the third
e.g. true ? 'yes' : 'no' returns 'yes'
The spread operator populates one object with the contents of
another. e.g. If a = { foo: 'Hello' } then
{ ...a, bar: 'World' } means { foo: 'Hello', bar: 'World' }
So your example takes the first list and If the ID matches the checkbox ID being targetted, it returns a new object with the state flipped, otherwise it returns the original object.
The net effect is a list of IDs with the "checked" status flipped on one of the items. Make sense?

Related

How to get a certain vaule from an array of Objects?

I am trying to create a cart layout that displays the number of quantity of each product listed in React.
The data of quantity is received from a redux state that comes like this:
[
{id: '630788107a0ce75d70be5350', quantity: 1, name: 'Nerea Sheppard', price: 176},
{id: '630788b388944200fdf6a6df', quantity: 1, name: 'Hollee Stanley', price: 423}
]
How to get the quantity each of the product?
const card = useSelector((state) => state.addons.cart);
addons.map((addon) => {
return (
<Button
onClick = {
() => {
dispatch(
REMOVE_FROM_CART({
id: addon._id,
})
);
}
} >
REMOVE ITEM
</Button>
<p>
// How to map and to get the quantity of each product from the card array
</p>
<Button onClick = {
() => {
dispatch(
ADD_TO_CART({
id: addon._id,
name: addon.name,
price: addon.price_in_euro_per_day,
})
);
}
} >
ADD ITEM
</Button>
)})
I guess the product-id is part of addon right? So I guess you want to find the product in the product-list which matches the addon._id?
There are serveral ways to do that, a simple, but a not a optimised solution would be"
// How to map and to get the quantity of each product from the card array
{card.find((item) => item.id === addon._id).quantity}
This will render the quantity directly into the html.
A second solution for quick access would be a hash-map and use the id as a key.
const cardMap = card.reduce((map, item) => {
map[item.id] = item;
return map;
}, {})
// In the html part:
<span>Quantity: {cardMap[addon._id].quantity}</span>
card?.find((x) => x.id === addon._id) ?
card?.find((x) => x.id === addon._id)
.quantity :
0

how to update object using index in react state?

suppose i am having an array of like
[
{ id: 1, name: "John" , selected: true}
{ id: 2, name: "Jim" , selected: false }
{ id: 3, name: "James" , selected: false }
]
I am having function which get id and on the basis of that id I want to change the selected property of object to true and other selected property object to false
here is my function what i have tried but its throwing error
const handleOnClick = (id) => {
const temps = state.findIndex((sub) => sub.id === id)
setState(prevState => ({
...prevState,
[prevState[temps].selected]: !prevState[temps].selected
}))
Use a .map() to iterate everything. You shouldn't change values within the array without recreating the tree down to the changed object. See below example.
Below you will:
map over every element
Spread their current values
Overwrite the selected depending on if the id is the newly "selected" id
I also supplied an additional function to update using the index of the item in the array instead of by id since your title is "how to update object using index in react state?", although your question also mentions changing by id. I would say go by id if you have the choice, array indices can change.
const App = () => {
const [state, setState] = React.useState([
{ id: 1, name: "John" , selected: true},
{ id: 2, name: "Jim" , selected: false },
{ id: 3, name: "James" , selected: false }
]);
// This takes the ID of the item
const handleOnClick = (id) => {
const newState = state.map(item => {
return {
...item,
selected: item.id === id
};
});
setState(newState);
};
// This takes the index of the item in the array
const handleOnClickByIndex = (indexToSelect) => {
const newState = state.map((item, idx) => {
return {
...item,
selected: indexToSelect === idx
};
});
setState(newState);
};
return (
<div>
{state.map((item, mapIndex) => (
<div key={item.id}>
<div>
<span>{item.name} is selected: {item.selected ? "yes" : "no"}</span>
{/* This will update by ID*/}
<button onClick={() => handleOnClick(item.id)}>Select using ID</button>
{/* This will update by the index of the array (supplied by map) */}
<button onClick={() => handleOnClickByIndex(mapIndex)}>Select using index</button>
</div>
</div>
))}
</div>
);
};
ReactDOM.render(
<App/>,
document.getElementById("app")
);
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="app"></div>

In ReactJS how do I keep track of the state of a group of checkboxes?

I am trying to keep track of which boxes are checked in my local state(you can check multiple boxes). I want to be able to check and uncheck the boxes and keep track of the ids of the boxes that are checked. I will do something with the values later. This is what I have so far:
import React, { Component } from 'react'
import './App.css'
import CheckBox from './CheckBox'
class App extends Component {
constructor(props) {
super(props)
this.state = {
fruits: [
{id: 1, value: "banana", isChecked: false},
{id: 2, value: "apple", isChecked: false},
{id: 3, value: "mango", isChecked: false},
{id: 4, value: "grape", isChecked: false}
],
fruitIds: []
}
}
handleCheckChildElement = (e) => {
const index = this.state.fruits.findIndex((fruit) => fruit.value === e.target.value),
fruits = [...this.state.fruits],
checkedOrNot = e.target.checked === true ? true : false;
fruits[index] = {id: fruits[index].id, value: fruits[index].value, isChecked: checkedOrNot};
this.setState({fruits});
this.updateCheckedIds(e);
}
updateCheckedIds = (e) => {
const fruitIds = [...this.state.fruitIds],
updatedFruitIds= fruitIds.concat(e.target.id);
this.setState({updatedFruitIds});
}
render() {
const { fruits } = this.state;
if (!fruits) return;
const fruitOptions = fruits.map((fruit, index) => {
return (
<CheckBox key={index}
handleCheckChildElement={this.handleCheckChildElement}
isChecked={fruit.isChecked}
id={fruit.id}
value={fruit.value}
/>
);
})
return (
<div className="App">
<h1>Choose one or more fruits</h1>
<ul>
{ fruitOptions }
</ul>
</div>
);
}
}
export default App
So basically I am able to check and uncheck the boxes, but I cannot seem to update and store the fruitIds. Here is my checkbox component also:
import React from 'react'
export const CheckBox = props => {
return (
<li>
<input key={props.id}
onChange={props.handleCheckChildElement}
type="checkbox"
id={props.id}
checked={props.isChecked}
value={props.value}
/>
{props.value}
</li>
)
}
export default CheckBox
Also if you have a cleaner ways to do this than the way I am doing it, I would love to see it.
This is what if I were to approach it I will do. I will create a one dimensional array that holds the id's of the fruits when A fruit if clicked(checked) I will add it id to the array and when its clicked the second time I check if the array already has the id I remove it. then the presence of id in the array will mean the fruit is checked otherwise its not checked So I will do something like below
this.state={
fruitsIds: []
}
handleCheckChildElement=(id) => {
//the logic here is to remove the id if its already exist else add it. and set it back to state
const fruitsIds = this.state.fruitsIds;
this.setState({fruitsIds: fruitsIds.contains(id) ? fruitsIds.filter(i => i != id) : [...fruitsIds, id] })
}
then I render the checkboxes like
<CheckBox key={index}
handleCheckChildElement={this.handleCheckChildElement}
isChecked = { this.state.fruitsIds.contains(fruit.id)}
id={fruit.id}
/>
This is because you can always use the id to get all the other properties of the fruit so there is absolutely no need storing them again.
then the checkbox component should be as follows
export const CheckBox = props => {
return (
<li>
<input key={props.id}
onChange={() => props.handleCheckChildElement(props.id)}
type="checkbox"
id={props.id}
checked={props.isChecked}
value={props.value}
/>
{props.value}
</li>
)
}
The reason you are not getting your ids updated because:
You are trying to concat a non array element to an array.
concat is used for joining two or more arrays.
updatedFruitIds = fruitIds.concat(e.target.id);
You are not updating your actual fruitIds state field. I dont know why you are using "updatedFruitIds" this variable but due to above error it will always result into a single element array.
this.setState({ updatedFruitIds });
updateCheckedIds = e => {
const fruitIds = [...this.state.fruitIds],
updatedFruitIds = fruitIds.concat([e.target.id]);
this.setState({ fruitIds: updatedFruitIds });
};
OR
updateCheckedIds = e => {
const fruitIds = [...this.state.fruitIds, e.target.id],
this.setState({ fruitIds });
};

when using {react-select} Cannot read property 'name' of undefined

I am very beginning to reactJS and front end
I added react-select npm for my dropdown like below, before added react-select everything is working fine. How to define name in Select?
<div className="container">
<div className="row">
<div className="col-md-4" />
<div className="col-md-4">
<Select
options={this.state.allGenres}
onChange={this.props.onDataChange}
name="genre"
/>
</div>
<div className="col-md-4" />
</div>
</div>
this is my array,
var Data = response.data;
const map = Data.map((arrElement, index) => ({
label: arrElement,
value: index
}));
example:
[
{
"label": "Action",
"value": 0
},
{
"label": "Comedy",
"value": 1
},
{
"label": "Documentary",
"value": 2
}
]
error message coming in here,
dataChange(ev, action) {
this.setState({
[ev.target.name]: ev.target.value
});
}
render()
render() {
return (
<Movie
onPostData={this.postData.bind(this)}
onDataChange={this.dataChange.bind(this)}
/>
);
}
Error
Uncaught TypeError: Cannot read property 'name' of undefined
at Movies.dataChange
You expect the first argument in react-select´s onChange method to be an event object, but it isn't.
The first argument is the selected option (or options if you have isMulti set).
There is also a second argument which is an object with the following attributes:
action: The action which triggered the change
name: The name given to the Select component using the name prop.
So if you want to use the name:
onDataChange={(value, action) => {
this.setState({
[action.name]: value
})
}}
Reference in source code
I worked around this method and it worked.
handleSelectChange: function(name) {
return function(newValue) {
// perform change on this.state for name and newValue
}.bind(this);
},
render: function() {
return (
<div>
<Select ...attrs... onChange={this.handleSelectChange('first')} />
<Select ...attrs... onChange={this.handleSelectChange('second')} />
</div>);
}
This is how you can get the value(s) of the selected option(s) and the name of the input as well.
For more info, check this issue on Github.
handleChange = (selectedOptions, actionMeta) => {
const inputName = actionMeta.name;
let selectedValues;
if (Array.isArray(selectedOptions)) {
// An array containing values of the selected options (like: ["one", "two", "three"]
selectedValues = selectedOptions.map(option => option.value);
// OR, use this if you want the values of the selected options as a string separated by comma (like: "one,two,three")
selectedValues = selectedOptions.map(option => option.value).join(",");
} else {
// An array containing the selected option (like: ["one"])
selectedValues = [selectedOptions.value];
// OR, use this if you want the value of the selected option as a string (like: "one")
selectedValues = selectedOptions.value;
}
// Do whatever you want with the selected values
//..
this.setState({
[inputName]: selectedValues
});
}
<Select
name="genre"
options={this.state.allGenres}
onChange={this.handleChange}
/>

What does this logic do in JavaScript?

I am learning react and came across a tutorial where a delete button is added in the JSX and a function has been defined to execute the event. However, I am confused what does the code below do.
const deleteList=this.state.list.filter(item=>item.objectID!==id);
In particular I am confused what does the below logic mean:
(item=>item.objectID!==id);
this.state.list.filter(item=>item.objectID!==id);
This part loops over all items in list, and returns a new array containing only items that match the condition item.objectID!==id
This is a common syntax to delete one element of a list.
See documentation of filter method.
It is similar to
function(item) {
return item.objectID!==id
}
Basically filter out all elements where id is not equal to item.objectID
For Better understanding I am explaining it with an example.
see the below code:-
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = {
list: [
{ id: '1', age: 42 },
{ id: '2', age: 33 },
{ id: '3', age: 68 },
],
};
}
onRemoveItem = id => {
this.setState(state => {
const list = state.list.filter(item => item.objectID !== id);
return {
list,
};
});
};
render() {
return (
<div>
<ul>
{this.state.list.map(item => (
<li key={item.objectID}>
The person is {item.age} years old.
<button
type="button"
onClick={() => this.onRemoveItem(item.objectID)}
>
Remove
</button>
</li>
))}
</ul>
</div>
);
}
}
export default App;
Above code we have React state array of objects (i.e. objectid and age).
while defining onRemoveItem methods id is the parameter.
when onRemoveItem methods is called on the button click event an item.objectID is passed as parameter.
onRemoveItem = id => {
this.setState(state => {
const list = state.list.filter(item => item.objectID !== id);
Here we filter the item from the React state array whose objectid is id and id is nothing but the objectid which is passed as a parameter on the onRemoveItem method calling.

Resources