'How to create a string array in the useState hook and update that same array in TypeScript?
I have a React project where I am trying to create a multi select function where you can select and deselect multiple avatars at once.
So far I have this:
export interface IStoreRecommendationProps {
title: string;
description: string;
discountNumber: number;
discountItem: string;
arr: string[];
onClickAvatar: () => void; // pass a specific parameter for avatar
}
export const StoreRecommendation: React.FC<IStoreRecommendationProps> = ({
title,
description,
discountNumber,
discountItem,
arr,
onClickAvatar,
...props
}) => {
const [visible, setVisible] = useState({
arr[],
});
const showIcon = (id) => {
arr.push(id);
console.log(arr);
setVisible(id);
onClickAvatar();
};
const displayContacts = () =>
CUSTOMERS.map((person) => (
<AvatarContainer>
<Avatar
picture={{uri: person.profile_picture}}
onPress={() => showIcon(person.customer_id)}
/>
<TextAvatar>{person.name}</TextAvatar>
{visible.includes(person.customer_id) && <CheckIcon />}
</AvatarContainer>
));
In the showIcon() I am trying to save an array of IDs in the state and update them accordingly(push if clicked, remove if clicked again) and then just check the array in displayContacts() by doing visible.includes(person.customer_id)
const [visible, setVisible] = useState({
arr[],
});
const showIcon = (id) => {
arr.push(id);
console.log(arr);
setVisible(id);
onClickAvatar();
};
const displayContacts = () =>
CUSTOMERS.map((person) => (
<AvatarContainer>
<Avatar
picture={{uri: person.profile_picture}}
onPress={() => showIcon(person.customer_id)}
/>
<TextAvatar>{person.name}</TextAvatar>
{visible.includes(person.customer_id) && <CheckIcon />}
</AvatarContainer>
));
I am grabbing customers from a seperate file and it looks like this:
export const CUSTOMERS = [
{
customer_id: '1',
name: "John Doe",
profile_picture: "https://img.freepik.com/free-photo/portrait-white-man-isolated_53876-40306.jpg?size=626&ext=jpg",
approval_status: false,
payment_method: Enums.OrderPaymentMethod.IN_PERSON
},
{
customer_id: '2',
name: "Evan Green",
profile_picture: "https://media.istockphoto.com/photos/portrait-concept-picture-id1016761216?k=6&m=1016761216&s=612x612&w=0&h=j-DyZTSqmnhoHKsJdGmiMPnungpHiq9UTrvx4UylMQI=",
approval_status: false,
payment_method: Enums.OrderPaymentMethod.IN_PERSON
},
{
customer_id: '3',
name: "Grace Lewis",
profile_picture: "https://img.freepik.com/free-photo/friendly-brunette-looking-camera_23-2147774849.jpg?size=626&ext=jpg",
approval_status: false,
payment_method: Enums.OrderPaymentMethod.IN_PERSON
}, ...]
Now when I try to do visible.includes() I get an error where it tells me my array is of type never. Am I doing the array initialization to the useState() hook wrong, and am I on the right track to do what I am attempting to do?
Solution 1:[1]
Try following, solves the issue (hopefully :)):
- Replace
const [visible, setVisible] = useState({ arr[],});
with
const [visible, setVisible] = useState<string[]>([]);
for proper initialisation and type definition
Replace
const showIcon = (id) => { arr.push(id); console.log(arr); setVisible(id); onClickAvatar(); };
with
const showIcon = (id) => {
setVisible(prevState => {
// check if it is already added
if(prevState.includes(id)) {
// clone the prevState arr to prevent side effects
const clone = [...prevState];
// Remove the existing id
clone.splice(prevState.indexOf(id), 1)
return clone;
} else {
return [...prevState, id]
}});
onClickAvatar();
};
Note: arr
is not relevant here as it is not used elsewhere and is redundant so it should be removed
Solution 2:[2]
You mean to be initializing visible
as an array and then interacting w/ that array via setVisible
, rather than a direct manipulation method.
Try something like this:
const [visible, setVisible] = useState([]);
const showIcon = (id) => {
setVisible([...visible, id])
console.log(visible);
onClickAvatar();
};
assuming your initial state of visible is an array of ids like [34, 63, 12]
and you call showIcon(20)
, it should update visible
and log out to [34, 63, 12, 20]
Solution 3:[3]
I was blocked and I tried everything... solution ?
The comment from Drew Reese
I suggest using functional updates, setVisible(visible => [...visible, id]) so state updates from previous state and not the state closed over in callback scope, and the console log will only log the current state, not what it will update to for the next render.
Just using this gave me bad result :
setVisible([...visible, id])
But perfect with :
setVisible(visible => [...visible, id])
A big thanks !
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Zoe stands with Ukraine |
Solution 3 | Serial Geeker |