Reputation: 311
I have a few components being rendered from an Array.map() that won't update even when the state (pertaining to said array) changes, and I have no clue why this is.
Home (main component) :
import React, { useState } from 'react';
import { View, TouchableOpacity } from 'react-native';
import { base } from './data';
import Indicator from './components/Indicator';
const Home = () => {
const [switches, setSwitches] = useState(base);
const handleToggle = (id: number) => {
base.map(switch => {
switch.on =
(switch.on && switch.id !== id) || (!switch.on && switch.id === id)
? !switch.on
: switch.on;
});
setSwitches(base);
};
return (
<View>
{switches.map(switch => (
<TouchableOpacity
onPress={() => handleToggle(switch.id)}
key={switch.id}
>
<Indicator
color={switch.color}
on={switch.on}
/>
</TouchableOpacity>
))}
</View>
Indicator component:
import React from 'react';
import { View } from 'react-native';
import { On, Off } from './Indicators';
interface IndicatorProps {
color: string;
on: boolean;
}
const Indicator: React.FC<IndicatorProps> = ({ color, on }) => {
return (
<View>
{on ? <On /> : <Off />}
</View>
);
};
export default Indicator;
I have verified that the state of switches
is changing as expected when clicking the touchable areas, but no visible change occurs in the components.
Upvotes: 1
Views: 2954
Reputation: 13216
I have verified that the state of switches is changing as expected
Are you 100% sure about this?
base.map(switch => {
switch.on =
(switch.on && switch.id !== id) || (!switch.on && switch.id === id)
? !switch.on
: switch.on;
});
setSwitches(base);
This code doesn't toggle the switch value. map
call calculates and returns the transformed array, but doesn't change it in place, and you then throw away the result, before calling setSwitches
every time with exact same untoggled base
value. In addition, you're toggling using base
, when it looks like you probably want to toggle the state of switches
.
You want something more like this:
setSwitches(switches.map(switch => {
switch.on =
(switch.on && switch.id !== id) || (!switch.on && switch.id === id)
? !switch.on
: switch.on;
}));
Upvotes: 0
Reputation: 1912
You need to setState with an entirely new object so that it does not pass a shallow comparison.
You can do something like:
const handleToggle = (id: number) => {
const newState = switches.map(switch => ({
...switch,
on: (switch.on && switch.id !== id) || (!switch.on && switch.id === id)
? !switch.on
: switch.on
}));
setSwitches(newState);
};
Upvotes: 1