最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to update an array by index using the useState hook? - Stack Overflow

programmeradmin3浏览0评论

I have a select ponent that I would like to use to update the values of an array of objects based on the index.

I use the hook like this:

const [areas, setAreas] = useState(product.areas);

This returns the following for "areas":

[
  0: {de: "Getraenke", en: "Drinks"},
  1: {de: "Snacks", en: "Snacks"}
]

My select ponent looks like this:

{areas?.map((area: {de: string, en: string}, index: number) => (
  <Wrapper key={index}>
    <Select
      label="Area"
      name="product-area"
      value={area[lang] || ''}
      onChange={e => setArea([...area, { [lang]: e.target.value }])}
    >
      {areaOptions.map(option => (
        <option value={option} key={option}>
          {option}
        </option>
      ))}
    </Select>
  </InputWrapper>
))}

In this way I unfortunately get the following for "area" after selecting an option (here "Sweets"):

[
  0: {de: "Getraenke", en: "Drinks"},
  1: {de: "Snacks", en: "Snacks"}
  2: {en: "Sweets" }
]

So the first object of the array is not updated as intended, but a further object is appended, which unfortunately also lacks the "de" language.

My goal is to update the first object (or the object based on the index of the select ponent) of the array so that instead of:

  0: {de: "Getraenke", en: "Drinks"}

..the updated object looks like this:

  0: {de: "Suessigkeiten", en: "Sweets"}

The objects within the array should therefore be updated based on the index of the current select ponent and also take into account the selected language (default "en").

I have a select ponent that I would like to use to update the values of an array of objects based on the index.

I use the hook like this:

const [areas, setAreas] = useState(product.areas);

This returns the following for "areas":

[
  0: {de: "Getraenke", en: "Drinks"},
  1: {de: "Snacks", en: "Snacks"}
]

My select ponent looks like this:

{areas?.map((area: {de: string, en: string}, index: number) => (
  <Wrapper key={index}>
    <Select
      label="Area"
      name="product-area"
      value={area[lang] || ''}
      onChange={e => setArea([...area, { [lang]: e.target.value }])}
    >
      {areaOptions.map(option => (
        <option value={option} key={option}>
          {option}
        </option>
      ))}
    </Select>
  </InputWrapper>
))}

In this way I unfortunately get the following for "area" after selecting an option (here "Sweets"):

[
  0: {de: "Getraenke", en: "Drinks"},
  1: {de: "Snacks", en: "Snacks"}
  2: {en: "Sweets" }
]

So the first object of the array is not updated as intended, but a further object is appended, which unfortunately also lacks the "de" language.

My goal is to update the first object (or the object based on the index of the select ponent) of the array so that instead of:

  0: {de: "Getraenke", en: "Drinks"}

..the updated object looks like this:

  0: {de: "Suessigkeiten", en: "Sweets"}

The objects within the array should therefore be updated based on the index of the current select ponent and also take into account the selected language (default "en").

Share Improve this question asked Dec 21, 2020 at 13:27 Codehan25Codehan25 3,01412 gold badges58 silver badges109 bronze badges 1
  • 1 In the onChange, you can write any logic you like... why don't you take "areas" array and modify/create a new array the way you want, and then call setAreas ? What am I missing? – Dima G Commented Dec 21, 2020 at 13:40
Add a ment  | 

2 Answers 2

Reset to default 11

The easiest way to do this is to clone the array, update the specific array item by index and then replace the old array with it using useState, like this.

const updateArea = (e, lang, index) => {
  const updatedAreas = [...areas];
  updatedArea[index][lang] = e.target.value;
  setAreas(updatedAreas);
}

...

{areas?.map((area: {de: string, en: string}, index: number) => (
  <Wrapper key={index}>
    <Select
      label="Area"
      name="product-area"
      value={area[lang] || ''}
      onChange={e => updateArea(e, lang, index)}
    >
      {areaOptions.map(option => (
        <option value={option} key={option}>
          {option}
        </option>
      ))}
    </Select>
  </InputWrapper>
))}

Let's solve this step by step

1. A further object is appended

That's because you're telling it to do so :)

onChange={e => setArea([...area, { [lang]: e.target.value }])}

This means, copy the entire array ...area and add a new object at the end { [lang]: e.target.value }

Another mistake you're making is not using a callback function, proper way to access current ...area should be this:

onChange={e => setArea((currentArea) => [...currentArea, { [lang]: e.target.value }]}

This way you always have the most up-to-date version of area.

Now, to update the specific object by the index, you would do the following:

onChange={e => setArea((currentArea) => {
  const { value } = e.target;
  
  const newArea = currentArea.map((singleArea, areaIndex) => {
    if (areaIndex === index) {
      return { [lang]: value }
    }
 
    return singleArea;
  });

  return newArea;
}}

2. Lacks the "de" language

Again, you're explicitly only adding one language to it :)

{ [lang]: value } // { en: 'something' }

Not sure how to fix this one for you, but at least you can understand why its wrong, It should be something like (just a concept, this won't work):

{ [langDe]: value, [langEn]: value } // { de: 'Guten Tag', en: 'something' }
发布评论

评论列表(0)

  1. 暂无评论