Home > Enterprise >  React useState not updating when called from Child Component
React useState not updating when called from Child Component

Time:10-19

I'm trying to create a resuable component that will be able to take a function passed down into it, allowing it to update the state of the parent component. I've got a demo on CodeSandbox that shows the issue.

TrackListing is passed the removeTrack function from the parent, and when the delete button is clicked inside the TrackListing, the function is called with the rows index to be removed from the tracks state. Unfortunately this doesn't seem to update the tracks state.

CodePudding user response:

Your not changing the state, tracks it's the same tracks.

In JS if you do -> var a = [1,23]; var b = a; console.log(a === b); it would return true. Assigning an array to another var, does not make a new array.. Doing var a = [1,23]; var b = [...a]; console.log(a === b); will do a shallow copy of a, and this as expected will return false. IOW: In react causing a state change.

Also splice(index,index), I'm pretty sure you meant splice(index, 1).

const removeTrack = (index: number) => {
    const t = tracks;
    t.splice(index, index);
    console.log(t);
    setTracks(t);  //t is still the same instance of t.
};

So you will need to make a copy of t.

const removeTrack = (index: number) => {
    const t = tracks;
    t.splice(index, 1);
    setTracks([...t]); //lets make a copy of `t` state has changed.
};

As pointed out in the comments, using the callback version of setState is a good idea, it will prevent issues of scope, here scope isn't an issue, but it's easy to get caught out by it.

Also another issue I've found with your current implementation you might want to look into, using array index as a key is not a good idea, it's not unique and you could get some funky rendering quirks, you really need unique ids for your tracks to use as the key

eg. This bit ->

tracks.map((track, index) => (
    <tr key={index}>   //not a good idea.

tracks.map((track, index) => (
    <tr key={track.id}>   //much better

Also when it comes to deleting, use the track id, using the callback/filter version in comments from Ali, you could also then just change removeTrack(track:Track) {}, and pass the track. IOW: remove index array positions from all code.

I've done a fork of your CodeSandBox with these changes to make it easier. CodeSandBox

  • Related