mnj
mnj

Reputation: 3423

Array reference behaving like a copy

I have a simple React app with a table of posts: enter image description here

In the beginning, the app always has 100 posts.

Here's how I handle DELETE operation:

  handleDelete = async post => {
    const oldPosts = this.state.posts;

    const posts = this.state.posts.filter(n => n.id !== post.id);
    this.setState({ posts });

    try {
      await axios.delete(`${apiEndpoint}/${post.id}`);
      console.log(oldPosts);
    } catch (e) {
      alert("There was an error while removing post " + post.id);
    }
  };

oldPosts variable contains a REFERENCE to posts array of state. As you can see in the next two lines, I'm updating state with a smaller amount of posts (99 of them). I would expect my oldPosts reference to point to this 99-element array. However, when it's console.logged, I see 100 elements. Why is that?

Upvotes: 1

Views: 59

Answers (4)

Jonas Wilms
Jonas Wilms

Reputation: 138327

  const oldPosts = this.state.posts;

That copies the reference to the array into the oldPost variable. If the array inside this.state.posts get changed, you will see those changes inside oldPosts, but if the reference itself gets changed, then oldPost and this.state.posts point to two different arrays.

Using .filter you do create a new array.

Upvotes: 2

Mayank Shukla
Mayank Shukla

Reputation: 104399

I would expect my oldPosts reference to point to this 99-element array. However, when it's console.logged, I see 100 elements. Why is that?

Nice question, let me try to explain. See the case is, array will be stored in some memory location and this.state.posts will have the ref to that array. You are referencing the same array by oldPosts, it means oldPosts is pointing to array not to this.state.posts.

When we update the value of this.state.posts, it will have a new ref, ref to newly created array, not to old array. But that oldPosts will still point to old array.

Even if you assign any value other than an array, it will never effect the value of oldPosts.

Check this example, you will get a better idea:

// consider this as state obj
let obj = {
  posts: [1, 2, 3, 4],
}

let oldPosts = obj.posts;
let newPosts = obj.posts.filter(el => el < 4);

// same as setState
obj.posts = newPosts;

// still point to old array
console.log('oldPosts', oldPosts);

// it will have the new array
console.log('obj.posts', obj.posts);

obj.posts = 10;

// now it will have a totally new value
console.log('obj.posts', obj.posts);

Check this another example:

let a = [1, 2, 3, 4];
let b = a;

/* 
  a and b both points to same array, but if we assign a 
   new value to a, b will still points to array
*/

a = 10;

// by changing the value of a, it will not affect b
console.log('a', a);

// still point to array
console.log('b', b);

Upvotes: 1

Umair
Umair

Reputation: 469

You are not updating your oldPosts state. this should work

  this.setState({ oldPosts : posts }); 

Thanks

Upvotes: 0

Zohaib Ijaz
Zohaib Ijaz

Reputation: 22885

You are assigning 100 posts to oldPosts. Then you are filtering posts to get a new array and saving in state. Filter returns a new array and does not updates the actual array i.e. oldPosts. If you want this behavior, you can use Array.prototype.splice

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice

Upvotes: 0

Related Questions