简体   繁体   English

在 reactjs 中使用 useState 挂钩更新对象数组

[英]Updating array of objects by using useState hook in reactjs

I have this state of array of object. I use them to create three cards.我有这个 state 的数组 object。我用它们来创建三张卡片。

const [option, setOption] = useState([{
    id: 1,
    label: "Borrowers",
    icon: FcApprove,
    counter: 2,
    link: "borrowers",
    color: "#5d8c6d",
    isActive: false,
  },
  {
    id: 2,
    label: "My Offer",
    icon: FaHandsHelping,
    counter: 2,
    link: "offer",
    color: "#04738a",
    isActive: false,
  },
  {
    id: 3,
    label: "Promise",
    icon: FaPrayingHands,
    counter: 2,
    link: "promise",
    color: "#40437a",
    isActive: false,
  }
]);

Whenever one of these cards is clicked, I would like to update the field isActive to true as follows.每当单击其中一张卡片时,我想将字段isActive更新为 true,如下所示。

function FixedHeader() {
  const [options, setOptions] = useState(option); //option is the above mentioned array of object
  const handleChange = (opt) => {
    setOption([option[index].isActive: true])
  }
  return < > {
    options.map((opt, index) => {
      <Card onClick={handleChange(opt,index)} key={index} className={opt.isActive ? "activecard": ""}>
        <CardContent>
          <Stack direction="column">
            <opt.icon size={20}/>
            <Typography>opt.label</Typography>
          </Stack>
        </CardContent>
      </Card>
    })
  }

My code somewhat looks the above one.我的代码有点像上面的代码。 but it is not literally changing isActive filed但它并没有真正改变isActive归档

You are mutating the options array.您正在改变options数组。 When you want to update an array stored in state, you need to create a new one (or make a copy of an existing one), and then set state to use the new array.当你想更新存储在 state 中的数组时,你需要创建一个新数组(或复制一个现有数组),然后设置 state 以使用新数组。

Below will fix your issue下面将解决您的问题

const handleChange = (options, index) => {
  setOption(options.map((option, i) =>  ({...option, isActive: i === index }));
}

options is an array. options是一个数组。 You will want to map the previous state array to the next state array, updating the specific element object by the id property.你会想要 map 之前的 state 数组到下一个 state 数组,通过id属性更新特定元素 object。

const [options, setOptions] = useState(option);

// Curried function to close over option id in callback scope
const handleChange = (id) => () => {
  setOption(options => options.map(option => option.id === id
    ? { ...option, isActive: true }
    : option
  );
}

options.map((opt) => (
  <Card
    key={opt.id}
    onClick={handleChange(opt.id)}
    className={opt.isActive ? "activecard" : ""}
  >
    <CardContent>
      <Stack direction="column">
        <opt.icon size={20} />
        <Typography>opt.label</Typography>
      </Stack>
    </CardContent>
  </Card>
)

There are several issues going on here, the first being you should be using the useCallback hook when you are updating anything set in useState :这里有几个问题,第一个是在更新useState中设置的任何内容时应该使用useCallback挂钩:

export default function FixedHeader() {
  const [options, setOptions] = useState(myOptions);

  const onClick = useCallback((id) => {
    setOptions(options.map((opt) => {
      if (opt.id === id) {
        opt.isActive = !opt.isActive
      }
      return opt
    })
  )}, [options])

  return (
    <div>
      {
        options.map((option) => (
          <div style={{ backgroundColor: option.isActive ? 'blue' : 'red' }}>
            <button onClick={() => onClick(option.id)}>{option.label}</button>
          </div>
        ))
      }
    </div>
  );
}

Note that I was rendering something different than you to test this out, so make sure instead of passing in the index you pass the option.id like so:请注意,为了测试这一点,我渲染的内容与您不同,因此请确保不是传递索引,而是传递option.id ,如下所示:

onClick={() => onClick(option.id)}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM