简体   繁体   中英

Array always get last value in each element

In my loop I create a new variable and set a new value each time its looping(obviously)

But when the loop is done and outside my loop I console.log() the array which is filled in the loop. Its logging every element with the value of the last element.

I've tried to use .push() to fill the array.

state = {
    dates: ['2019-02-04', '2019-02-05', '2019-02-06'],
    entry: {
        value1: undefined,
        value2: undefined,
        value3: {
            value3_1: undefined,
            value3_2: undefined
        },
        date: undefined
    }
}

functionToFillArray() {
    let entries = [],
        entry = this.state.entry;

        entry.value1 = 'value1';
        entry.value2 = 'value2';
        entry.value3 = {
            value3_1: 'value3_1',
            value3_2: 'value3_2'
        };

    this.state.dates.forEach((date, i) => {
        entry.date = date;

        entries.push(entry);
    });

    console.log(entries);
}

The output that I would expect is:

[
    {
        value1: 'value1',
        value2: 'value2',
        value3: {
            value3_1: 'value3_1',
            value3_2: 'value3_2'
        },
        date: '2019-02-04'
    },
    {
        value1: 'value1',
        value2: 'value2',
        value3: {
            value3_1: 'value3_1',
            value3_2: 'value3_2'
        },
        date: '2019-02-05'
    },
    {
        value1: 'value1',
        value2: 'value2',
        value3: {
            value3_1: 'value3_1',
            value3_2: 'value3_2'
        },
        date: '2019-02-06'
    }
]

The value I get(Always the same date):

[
    {
        value1: 'value1',
        value2: 'value2',
        value3: {
            value3_1: 'value3_1',
            value3_2: 'value3_2'
        },
        date: '2019-02-06'
    },
    {
        value1: 'value1',
        value2: 'value2',
        value3: {
            value3_1: 'value3_1',
            value3_2: 'value3_2'
        },
        date: '2019-02-06'
    },
    {
        value1: 'value1',
        value2: 'value2',
        value3: {
            value3_1: 'value3_1',
            value3_2: 'value3_2'
        },
        date: '2019-02-06'
    }
]

Your code mutates the same this.state.entry object in each iteration and pushes that single object reference again and again to the array, so in the end that array indeed contains several entries, but all having the same object reference.

All in all, the this.state.entry value -- which you seem to want to use like a template -- really serves no purpose. You anyway are assigning new values to all of its properties. So there seems no need for it.

Just replace this:

let entry = this.state.entry;

with:

let entry = {};

Now entry will be a newly created object in each iteration.

Updated Question - Updated Answer

After the edit to your question, you only assign a date property to the same object over and over again.

The principle remains the same. Now replace this:

functionToFillArray() {
    let entries = [],
        entry = this.state.entry;
    entry.value1 = 'value1';
    entry.value2 = 'value2';
    entry.value3 = {
        value3_1: 'value3_1',
        value3_2: 'value3_2'
    };
    this.state.dates.forEach((date, i) => {
        entry.date = date;
        entries.push(entry);
    });
    console.log(entries);
}

...with:

functionToFillArray() {
    let entries = this.state.dates.map((date, i) => {
        return {
            value1: 'value1',
            value2: 'value2',
            value3: {
                value3_1: 'value3_1',
                value3_2: 'value3_2'
            },
            date
        };
    });
    console.log(entries);
}

This way you create a new object in each iteration. There is no gain to first initialise an object and then overwrite each of its properties, as then you still are working with a single object. You need a new one each iteration.

Note that the Array's map method is more useful here than forEach , but it is not related to your problem.

Use destructuring.

 const state = { dates: ['2019-02-04', '2019-02-05', '2019-02-06'], entry: { value1: undefined, value2: undefined, value3: { value3_1: undefined, value3_2: undefined }, date: undefined } }; function ToFillArray() { let entries = []; state.dates.forEach((date, i) => { const entry = { ...state.entry, value1: 'value1', value2: 'value2', value3: { value3_1: 'value3_1', value3_2: 'value3_2' }, date }; entries.push(entry); }); console.log(entries); } ToFillArray(); 

You aren't creating a copy, you are creating a link to this.state.entry and after that creating circular objects. Try creating a copy first.

...
this.state.dates.forEach((date, i) => {
        let entry = {...this.state.entry};
...

This is because you are always referring to the same variable instead of copying it, modifying the state, try this instead:

let stateCopy= {...this.state};
let entry = stateCopy.entry

    entry.value1 = 'value1';
    entry.value2 = 'value2';
    entry.value3 = {
        value3_1: 'value3_1',
        value3_2: 'value3_2'
    };
    entry.date = date;

    entries.push(entry);

You can refer to this article for a more detailed explanation :)

Also in this particular case it's not really necessary to re-use the object in the state since you assign the properties each time

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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