我正在尝试使用useRef更改从动态json列表中按下的按钮的颜色。但是当我使用useRef时,它只针对列表的最后一个值。但是如果我在列表中添加数组,那么主组件如何知道按下了哪个元素?
需要将选中项目的背景设为彩色,其余部分设为白色
父元素==
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>
);
};
子组件
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>
);
}
);
11月28日更新
获得选定的项目,但现在它正在改变每个按钮的颜色。
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;
子组件
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;
}
您正在将单个引用传递给所有,因此它仅保存最后一个值并覆盖所有先前的值。您必须创建与项目长度一样多的引用
import * as React from 'react';
import { Text, View, StyleSheet,Pressable } from 'react-native';
import Constants from 'expo-constants';
export default function App() {
const data = [{name:'wqh',id:12},{name:'dj',id:1212}]
const invoiceTitleRef = [] //Array of refs
const onChange = (index, selectedTitle) => {
console.log(index, selectedTitle) //you have your index and selected value of the item
console.log('Selected Title => ', invoiceTitleRef[index].getSelectedTitle())
}
return (
<View style={{ marginTop: 50,flex:1,backgroundColor:'green' }}>
{data.map((item, index) => (
<InvoiceTitle
index={index}
ref={ref => invoiceTitleRef[index]=ref}
key={item.id} title={item.name}
onChange={onChange} />
))}
</View>
)
}
const InvoiceTitle = React.forwardRef(({
title,
onChange,
index,
...props
}: InvoiceTitleProps, ref) => {
const[selectedTitle, setSelectedTitle] = React.useState('')
React.useImperativeHandle(ref, () => ({
getSelectedTitle : () => title
}))
const onClick = () => {
setSelectedTitle(title)
onChange(index,selectedTitle)
}
return (
<Pressable
onPress={onClick}
style = {({pressed}) => [styles.titleContainer,
{backgroundColor : 'red', opacity : pressed ? 0.5 : 1}]}>
<Text>{title}</Text>
</Pressable>
)
})
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
titleContainer:{
margin:20,
padding:20
}
});
另一种方式:-这种方式你不需要使用ref。您在父组件内的onChange方法中有索引和值,现在您知道按下哪个项目可以保存在数组中或直接使用它。(不需要使用任何ref)
现在已经修复了。我添加的新属性是选择的:'true',我将true保留在字符串中,但必须是布尔值导致这种折磨无法修复。