How to use "if" inside useState prevState map - reactjs

Does anybody know how can i use if statement like this.
This example doesnt work
uppy.on('complete', (result) => {
result.successful.forEach((file) =>
setImgs((prevState) =>
prevState.map((item) => {
if(item.id === file.id) {
return {
...item,
image: file.preview
}
}
})
)
)
})
And this works, but there s no if
uppy.on('complete', (result) => {
result.successful.forEach((file) =>
setImgs((prevState) =>
prevState.map((item) => ({
...item,
image: file.preview,
}))
)
)
})

I don't think you need to map if you're just trying to find an item.
You could do
const item = prevState.find(x.id ==> file.id)
return item? {...item.image:file.preview} : null

"doesn't work" will need more specification. Out of observation I can tell that it needed to have else statement or without, in order to return item if no change is required. The variable - item is unchanged element of imgs array, which we put back.
This is after refactoring your pseudocode:
uppy.on("complete", (result) => {
result.successful.forEach((file) =>
setImgs((prevState) =>
prevState.map((item) => {
if (item.id === file.id) {
return { id: item.id, image: file.preview };
} else return item;
})
)
);
});
Check the sandbox here

Since you are using a map that returns a new array, also you are trying to add an image key to the matched item only then, you need to also return for the else case.
const data = state.map((item) => {
if (item.id === file.id) return { ...item, image: file.preview };
return item;
});

Related

Why map() returns the value for all elements

There is an array of objects {id, value, active(true/false)}. When I click on an element, I set the active property to true and add this object to another array in state. When two elements appear in another array, then I do a check in useEffect, if the value of these elements are equal, then I do nothing, just clear array. If the values are not equal, then I want to change the active property to false for these elements in the first array. But for some reason, false changes for all elements, although there is a condition.
const [memoryGameItems, setMemoryGameItems] = useState(data)
const [currentItems, setCurrentItems] = useState([])
const choosingItem = (id, value) => {
setMemoryGameItems(memoryGameItems.map(item => {
if (id === item.id) {
return { ...item, active: true }
}
return item
}))
setCurrentItems([...currentItems, { id, value }])
}
useEffect(() => {
if (currentItems.length === 2) {
if (currentItems[0].value === currentItems[1].value) {
setCurrentItems([])
} else {
setTimeout(() => {
setMemoryGameItems(memoryGameItems.map(item => {
if (item.id === currentItems[0].id || currentItems[1].id) {
return { ...item, active: false }
}
return item
}))
setCurrentItems([])
}, 500)
}
}
// eslint-disable-next-line
}, [currentItems])
This item.id === currentItems[0].id || currentItems[1].id will always evaluate to true if currentItems[1].id is truthy.
You probably want something like item.id === currentItems[0].id || item.id === currentItems[1].id, I think.

How to useState to update mutiple items in an array of objects?

let initialData = [
{ id: 1, value: "EXPLORER", status:false, name:'explorer'},
{ id: 2, value: "YIDINJI-ADMIN", status:false, name:'yidinji' }]
let [data,setData] = useState(initialData)
The above give data is my initial state of array, Sometimes I have to update multiple items using a single map function
let newData = await data.map(item => {
(item.id === 1)? {...item, status : true} : item;
(item.id === 2)? {...item, status : true} : item;
})
setData(newData)
I have tried multiple ways to update the status of two data in a single map function, but nothing is working. Help will be appreciated!
You forgot return in map. Just add return like this:
let newData = await data.map((item) => {
return item.id === 1 ? { ...item, status: true } : item;
});
setData(newData);
Update, if you want update multyiple items, you can do like this:
let newData = await data.map((item) => {
let result = item;
if (item.id === 1 || item.id === 2) {
result = { ...item, status: true };
}
return result;
});
setData(newData);
This will help you. You forgot to return item.
let newData = data.map(item => {
if (item.id === 1 || item.id===2){
item.status=true
}
return item
})

React prevState parameter with map Function in setState

I am want to implement toggle functionality. (I have always used prevState to perform toggle operation) But in this case if I use prevState within map function. It is displaying error that "prevState is undefined".
I am posting 2 code, first one is working without prevState...but I want to implement it using prevState as shown in example enter code here2 (but 2nd code is giving the above mentioned error)
Correct:
this.setState({
rawData: this.state.rawData.map(a => {
if(a.id === id){
a.completed = !a.completed
}
return a
})
})
example 2:
this.setState((prevState)=>{
rawData: this.state.rawData.map(a => {
if(a.id === id){
a.completed = !prevState.a.completed
}
return a
})
})
I think the mapping is incorrect from the second example because you aren't mapping from the prevState. prevState.a is likely what is undefined. You need to also shallow copy the element being updated, otherwise a.completed = !a.completed is considered a state mutation.
this.setState(prevState => ({
rawData: prevState.rawData.map(a => {
if (a.id === id) {
return {
...a,
completed: !a.completed,
}
}
return a
})
}))
this.setState((prevState)=>({
rawData: prevState.rawData.map(a => {
if(a.id === id){
a.completed = !a.completed
}
return a
})
}))
Try this.

React native push with multiple key and value

I have a group of checkboxes, whenever I select a checkbox I need to push an array of data, like { 'index':1, 'photo':'sample.png' } to state, and whenever I unselecting the checkbox, I need to remove it from the state. after I need to loop through the state to get index and photo to be used
handleSelection = async (media, index, isSelected) => {
alert(index);
if (isSelected == true) {
this.state.mediaSelected.push(media.photo);
} else {
this.state.mediaSelected.splice(this.state.mediaSelected.indexOf(media.photo), 1);
}
console.warn(this.state.mediaSelected);
}
this is working for single value without the key, is there any way to push it with key and value?
You should always update state with this.setState in your case would be something like this:
handleSelection = async (media, index, isSelected) => {
alert(index);
if (isSelected == true) {
this.setState({
mediaSelected: this.state.mediaSelected.push({
index,
photo: media.photo
})
});
} else {
this.setState({
mediaSelected: this.state.mediaSelected.splice(this.state.mediaSelected.indexOf(media.photo), 1)
});
}
console.warn(this.state.mediaSelected);
}
Try this:
Sorry I am working as well as answering your question so it is taking time.
handleSelection = async (media, index, isSelected) => {
let selectPhotosObj = this.state.selectPhotosObj || [];
if (isSelected == true) {
const data = { index, photo: media.photo };
//this.state.selectedPhotoObj will be the container for your object.
selectPhotosObj.push(data)
//need to set the new Array of Object to the state.
this.setState({ mediaSelected: media.photo, selectPhotosObj });
} else {
const removedPhoto = this.state.mediaSelected.filter(value => value !== media.photo);
selectPhotosObj = this.state.selectedPhotosObj.filter(value => value.index !== index);
this.setState({
mediaSelected: removedPhoto,
selectPhotosObj
})
}
console.warn(selectPhotosObj);
}

ReactJS: Check if array contains value else append

I'm trying to check if a JSON response contains a value already inside an array and if it doesn't add it in. The problem I'm having is understanding how to approach this in reactjs. I'm checking before I append it but it doesn't want to work. I've tried passing in user object & user.id but these fail. The attempt below fails to compile but it should help understand what I'm trying to achieve.
Code:
componentWillMount() {
fetch('http://localhost:8090/v1/users')
.then(results => {
return results.json();
})
.then(data => {
data.map((user) => (
if(userList.hasOwnProperty(user.id)) {
userList.push({label: user.title, value: user.id})))
}
})
}
map return the resultant array, but you are not returning anything from it, you should instead use forEach Also you need to check if the userList array contains the id, for that you can use findIndex
What you need is
state = {
userList: [];
}
componentDidMount() {
fetch('http://localhost:8090/v1/users')
.then(results => {
return results.json();
})
.then(data => {
const newUserList = [...this.state.userList];
data.forEach((user) => { // use { here instead of
if(userList.findIndex(item => item.value === user.id) < 0) {
newData.push({label: user.title, value: user.id})
}
})
this.setState({userList: newUserList});
});
}
render() {
return (
{/* map over userList state and render it here */}
)
}
I'd recommend using reduce to turn the returned data into an array you'd like, then adding those values to your existing user list:
fetch('http://localhost:8090/v1/users')
.then(res => res.json())
.then(data => data.reduce((acc, user) => {
const idList = userList.map(user => user.id);
if (idList.indexOf(user.id) === -1) {
acc.push({label: user.title, value: user.id})
}
return acc;
},[]))
.then(newList => userList = [...userList, ...newList]);

Resources