Ala Ben Aicha
Ala Ben Aicha

Reputation: 1276

Fill an object dynamically in react with values from an array

I'm trying to fill an object with values that I'm getting from an array of objects but it's not working as expected.

This is a simplified code example

https://codesandbox.io/s/crazy-nobel-c7xdb?file=/src/App.js

import "./styles.css";
import React, { useEffect, useState } from "react";

export default function App() {
  const [fieldsValues, setFieldsValues] = useState({});
  const items = [{ value: "a" }, { value: "b" }, { value: "c" }];

  useEffect(() => {
    items.map((item, index) => {
      return setFieldsValues({
        ...fieldsValues,
        [index]: item.value
      });
    });
  }, []);

  return (
    <div className="App">
      <h2> {` fieldsValues = ${JSON.stringify(fieldsValues)}`} </h2>
    </div>
  );
}

I want the fieldsValues to return this:

{
  0: "a",
  1: "b",
  2: "c"
}

What I'm getting now:

fieldsValues = {"2":"c"}

Upvotes: 0

Views: 923

Answers (3)

Ori Drori
Ori Drori

Reputation: 192287

To create the object map the array to [index, value] pairs, and convert to an object with Object.fromEntries():

const items = [{ value: "a" }, { value: "b" }, { value: "c" }];

const result = Object.fromEntries(items.map(({ value }, index) => [index, value]))

console.log(result)

However, the way you are using the array, and then need to set the state doesn't actually makes sense in the react context.

If the array is a prop, you should add it to useEffect as a dependency:

const arrToObj = items => Object.fromEntries(items.map(({ value }, index) => [index, value]))

export default function App({ items }) {
  const [fieldsValues, setFieldsValues] = useState({});

  useEffect(() => {
    setState(() => arrToObj(items))
  }, [items]);
  
  ...

If it's a static array, set it as the initial value of setState:

const arrToObj = items => Object.fromEntries(items.map(({ value }, index) => [index, value]))

const items = [{ value: "a" }, { value: "b" }, { value: "c" }];
    
export default function App({ items }) {
  const [fieldsValues, setFieldsValues] = useState(() => arrToObj(items));
      
  ...

Upvotes: 1

RamTn
RamTn

Reputation: 99

By your way It would be like this

  useEffect(() => {
    let test={}
    items.map((item, index) => {
      return setFieldsValues((prev)=>{
        return {
        ...prev,
        [index]: item.value
      }
      });
    });
  }, []);

Upvotes: 0

Rahul Sharma
Rahul Sharma

Reputation: 10111

You fix it by doing this

useEffect(() => {
  items.map((item, index) => {
    return setFieldsValues((prev) => ({
      ...prev,
      [index]: item.value,
    }));
  });
}, []);

Better way of doing this is

useEffect(() => {
  const data = items.reduce(
    (prev, item, index) => ({ ...prev, [index]: item.value }),
    {}
  );

  setFieldsValues((prev) => ({ ...prev, ...data }));
}, []);

Upvotes: 3

Related Questions