提问者:小点点

尝试使用useRef更改从动态列表中按下的按钮的颜色以提升状态[React Native]


我正在尝试使用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;
}

共2个答案

匿名用户

您正在将单个引用传递给所有,因此它仅保存最后一个值并覆盖所有先前的值。您必须创建与项目长度一样多的引用

  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保留在字符串中,但必须是布尔值导致这种折磨无法修复。