I am trying to change the color of a button pressed from a dynamic json list using useRef. But when I use the useRef it is only aiming at the last value of the list.But if I add array in the list then how would the main component know which element was pressed ?
Need to make the background of the selected item colored and rest white
Parent Element
==> InvoiceTitle is the child component
const Usage = () => {
const data = UsageDataMock;
const invoiceTitleRef = useRef("");
const onChange = () => {
console.log(
"Selected Title => ",
invoiceTitleRef?.current?.getSelectedTitle()
);
};
return (
<View style={{ flexDirection: "row", marginTop: 50 }}>
{data.map((item, index) => (
<InvoiceTitle
ref={invoiceTitleRef}
key={item.id}
title={item.title}
onChange={onChange}
/>
))}
</View>
);
};
Child Component
const InvoiceTitle = forwardRef(
({ title, onChange, ...props }: InvoiceTitleProps, ref) => {
const [selectedTitle, setSelectedTitle] = useState("");
useImperativeHandle(ref, () => ({
getSelectedTitle: () => selectedTitle,
}));
const onClick = (title: string) => {
onChange(selectedTitle);
};
console.log("default title", selectedTitle);
return (
<Pressable
onPress={() => onChange(setSelectedTitle(title))}
style={({ pressed }) => [
styles.titleContainer,
{ backgroundColor: "red", opacity: pressed ? 0.5 : 1 },
]}
>
<AppText>{title}</AppText>
</Pressable>
);
}
);
Updated 28th Nov
Getting selected items but now it is changing color of every button .
const Usage = () => {
const [data, setData] = useState(UsageDataMock1);
const invoiceTitleRef = [];
const onChange = (index, selectedTitle) => {
// console.log('Selected Title => ', invoiceTitleRef[index].getSelectedTitle())
const tempSelection = invoiceTitleRef[index].getSelectedTitle();
const temp = data.map((item, index) => {
if (item.title == tempSelection) {
return { ...item, isSelected: "true" };
} else return { ...item, isSelected: "false" };
});
setData(temp);
};
console.log("123", data);
return (
<AppBackground>
<View style={{ flexDirection: "row", marginTop: 50 }}>
{data.map((item, index) => (
<>
{console.log("asd", item)}
<InvoiceTitle
ref={(element) => (invoiceTitleRef[index] = element)}
key={item.id}
title={item.title}
selected={item?.isSelected}
onChange={onChange}
index={index}
/>
</>
))}
</View>
</AppBackground>
);
};
const styles = StyleSheet.create({
container: {
flexDirection: "row",
marginTop: 40,
},
titleContainer: {
marginHorizontal: 10,
alignSelf: "flex-start",
paddingHorizontal: 10,
paddingVertical: 8,
borderRadius: 12,
},
});
export default Usage;
Child Component
const InvoiceTitle = forwardRef(
(
{
title,
onChange,
index,
key,
selected = false,
...props
}: InvoiceTitleProps,
ref
) => {
useImperativeHandle(ref, () => ({
getSelectedTitle: () => title,
}));
// console.log('ASD title', title, selected)
// const [color, setColor] = useState('white')
const [color, setColor] = useState("white");
const onClick = () => {
onChange(index, title);
};
return (
<Pressable
key={key}
onPress={() => onClick()}
style={({ pressed }) => [
styles.titleContainer,
{
backgroundColor: selected ? "red" : "blue",
opacity: pressed ? 0.5 : 1,
},
]}
>
<AppText>{title}</AppText>
</Pressable>
);
}
);
const styles = StyleSheet.create({
container: {
flexDirection: "row",
marginTop: 40,
},
titleContainer: {
marginHorizontal: 10,
alignSelf: "flex-start",
paddingHorizontal: 10,
paddingVertical: 8,
borderRadius: 12,
},
});
export default InvoiceTitle;
interface InvoiceTitleProps {
title: string;
onChange: Function;
index: number;
selected: boolean;
key?: number;
}
2
Answers
Fixed now. the new property that I was adding isSelected : 'true', I kept the true in string but it had to be Boolean that caused this ordeal not to fix.
you are passing a single ref to all so it saves only last value and overwrites all previous ones.
you have to create as many refs as the length of your items
another way :-
this way you don’t need to use ref. you have index and value in your onChange method inside parent component and now you know which item is pressed you can save in array or just use it.(don’t need to use any refs )