Having Difficulty with Splicing Arrays in React?

Currently working on learning React and trying to develop my own mini-app. I'm basing it very closely on the project showcased in this video tutorial.

I've run into an issue with the comment deletion functionality in my app. Despite searching various resources for similar problems, it seems like the error lies within my code (but I can't seem to pinpoint it). I've gone through the Babel file multiple times, but haven't been able to identify any mistakes.

Here are the specifics of the problem: When a new comment is created, users have the option to save or delete it using buttons. If only one comment exists and you click "Save," the delete function works correctly. However, if there are multiple comments and you try to delete the first one, it ends up deleting the next comment instead.

Hopefully that explanation makes some sense.

Can anyone help me spot the error? The logic behind the delete function can be found on line 71 under the name "deleteComment."

Check out the full code on CodePen.

var CommentSection = React.createClass({

    getInitialState: function() {
        return {editing: true}
    },

    edit: function() {
        this.setState({editing: true});
    },

    save: function() {
        this.props.updateCommentText(this.refs.newText.value, this.props.index);
        this.setState({editing: false});
    },

    delete: function() {
        this.props.deleteFromCard(this.props.index);
    },

    renderNormal: function() {
        return (
            <div className="comment-section">
                <div className="comment-content">{this.props.children}</div>
                <a className="-edit" onClick={this.edit}>Edit</a>
            </div>
        );
    },

    renderEdit: function() {
        return (
            <div className="comment-section">
                <textarea ref="newText" defaultValue={this.props.children}></textarea>
                <button className="-save" onClick={this.save}>Save</button>
                <button className="-delete" onClick={this.delete}>Delete</button>
            </div>
        );
    },

    render: function() {
        if(this.state.editing) {
            return this.renderEdit();
        } else {
            return this.renderNormal();
        }
    }

});

var PhotoSection = React.createClass({

    render: function() {
        return <div className="photo-section"></div>;
    }

});

var Desk = React.createClass({

    getInitialState: function() {
        return {
            comments: []
        }
    },

    addComment: function(text) {
        var arr = this.state.comments;
        arr.push(text);
        this.setState({comments: arr})
    },

    deleteComment: function(i) {
        console.log(i);
        var arr = this.state.comments;
        arr.splice(i, 1);
        this.setState({comments: arr})
    },

    updateComment: function(newText, i) {
        var arr = this.state.comments;
        arr[i] = newText;
        this.setState({comments: arr})
    },

    commentFormat: function(text, i) {
        return (
            <CommentSection key={i} index={i} updateCommentText={this.updateComment} deleteFromCard={this.deleteComment}>
                {text}
            </CommentSection>
        );
    },

    render: function() {
        return (
            <div className="desk">
                <div className="card">
                    <PhotoSection />
                    <div className="comment-section-backing">
                        <button className="-comment" onClick={this.addComment.bind(null, "")}>Leave a Comment</button>
                        {this.state.comments.map(this.commentFormat)}
                    </div>
                </div>
            </div>
        );
    }

});

ReactDOM.render(<Desk />, document.getElementById('app'));

Answer №1

The root of your issue lies in using the index as keys within your code:

https://facebook.github.io/react/docs/lists-and-keys.html#keys

After removing an item from your array, the state's array is updated correctly. However, upon rendering the array, all keys remain the same except for the missing element.

This leads to reconciliation taking place, causing your components to rerender. The issue arises from having (uncontrolled) textarea components within each component, each maintaining its own internal state. These uncontrolled textareas receive their initial value from the children prop, but do not reflect changes to that value. Therefore, when the components are rerendered with new values for text, the textarea instances retain their original values.

If the components' keys were not tied to the index during mapping, the correct component would be removed effectively.

edit: The code snippet has been updated slightly on the pen, featuring two distinct rendering branches (editing, normal). As the normal render path does not utilize uncontrolled textarea inputs, the erratic behavior is no longer evident on the pen.

Answer №2

An issue arose when utilizing this.props.children while rendering the CommentSection component

To resolve this, the code was modified to use a prop:


return (
      <div className="comment-section">
        <div className="comment-content">{this.props.commentText}</div>
        <a className="-edit" onClick={this.edit}>Edit</a>
        <button className="-delete" onClick={this.delete}>Delete</button>
      </div>
   );

This change was made in the commentFormat function within the container:


commentFormat: function(text, i) {
  return (
    <CommentSection 
      key={i} 
      index={i} 
      updateCommentText={this.updateComment}       
      deleteFromCard={this.deleteComment} 
      commentText={text}>
    </CommentSection>
  );
}

These adjustments seem to have resolved the issue.

CodePen

Answer №3

Experiment with Array.filter method to remove a comment.

removeComment: function(i) {
    var newArray = this.state.comments.filter(function(comment) {
        return comment.index !== i;
    });
    this.setState({comments: newArray});
},

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I'm running into some issues with flexbox and I'm in need of some assistance to find

I positioned two divs next to one another, but instead of each taking up 100vw, they are both sharing 50% of the available space. Is there a solution for this issue? Thank you. Page Image import type { AppProps } from "next/app"; import "./global.cs ...

How to Utilize findIndex to Validate the Presence of Elements in an Array of Objects using TypeScript

I need assistance in checking which properties from an array are present in another array of objects and which ones are not. My object structure is as follows: var tempObj=[{id: '1', color: 'red, blue, green', age: 27},{id: '2& ...

Guide on integrating a custom language parser and syntax validation into Monaco editor

I am in need of guidance on how to define a custom language in the Monaco editor. Despite my efforts, I have been unable to locate a reliable source for this documentation. My goal is to create a language with syntax similar to JavaScript, enabling users ...

Understanding MUI5 prop handling

Recently, I decided to experiment with Material UI 5 sx props just for fun. I encountered a bit of confusion while trying to replicate the behavior of the previous MUI 4 makeStyles function. Specifically, I was attempting to pass JSS classnames to sx props ...

The page reloads automatically following the completion of an ajax request

Hey there, I have a basic form with just a text field. When we submit the form, the data entered in the text field gets stored in the database through ajax. Although the ajax function is working properly and the data is being submitted, the page automatica ...

Creating a stylish table in React.js using material-ui, with each cell representing a unique element

My goal is to create a table where each product is represented in a cell. However, I've run into an issue with JSX that's preventing me from returning jsx without closing tags. The error message I'm receiving is unclear and I keep encounteri ...

Is there anyone who can clarify the operations happening within this Three.js StereoEffect code?

Is there anyone knowledgeable in stereo rendering who can provide an explanation of how these functions work together to achieve the VR stereo effect? Information on functions like StereoCamera(), setScissor(), setViewPort() in the three.js library seems s ...

What is the reason behind using <script> tag for scripts, instead of using <style> tag for external CSS files?

A family member who is new to Web Development posed an interesting question to me. Why do we use <script src="min.js"></script> and <link rel="stylesheet" href="min.css">? Why not simply use <style href="min.css"></style>? Wh ...

Passing information from the created hook to the mounted hook in VueJS

How can I transfer data from the created function to the mounted function in VueJS? In my VueJS application, the code in my created function is as follows: created: function(){ $.getJSON({ url: 'static/timeline.json', success:function( ...

What steps can I take to resolve the error message 'throw er; // Unhandled 'error' event' in my code's lifecycle?

Attempting to create a React app, I utilized the command prompt. Unfortunately, upon creation of the app and trying to start npm, various errors were encountered. In an attempt to create React apps using WebStorm, IntelliJ, Visual Studio Code, and PowerSh ...

When attempting to invoke the rest function, an error occurs stating that the dataService.init in Angular is not

Learning AngularJS has been my current focus. To practice, I have been working on a Quiz app tutorial. However, I encountered an issue when trying to call the rest function of a factory after injecting it into one of my controllers. The JSON data for this ...

Perform an Ajax call just one time

$('#addToCart').click(function () { let csrf = $("input[name=csrfmiddlewaretoken]").val(); let trTable = $(this).parents('div')[1]; let customPrice = $($(trTable).children('div') ...

Developing dynamic image import functionality using React

I'm currently developing a React application that requires dynamic display of images stored in large quantities on a server-side file system. Despite trying various solutions, including those recommended for similar issues, I have yet to find success. ...

Customize your React admin input component with a unique text input style

I recently developed a customized DateTimePicker component for my react-admin project: import { DateTimePicker, DateTimePickerProps, MuiPickersUtilsProvider } from "@material-ui/pickers"; import { FC } from "react"; import { FieldTitle, ...

Encountered a problem while rendering the app: [TypeError: Unable to assign a value to the property 'content' since it is undefined]. Implementing Express with

My experience with res.render is flawless: res.render('main', function(err, html){ // Displays '<html></html>' from 'views/main.html' console.log(html); }); However, the situation changes when it comes to ...

What could be causing the createReadStream function to send a corrupted file?

My current task involves generating a file from a URL using the fs module to my local system. Initially, everything seems successful. However, when attempting to post this file into a group using the createReadStream() function, I encounter an issue where ...

Include a triangle shape at the top of a div container that has a background image using CSS

Struggling to add a point or triangle shape to my div with a background image, finding it difficult to create enough open space. This is the desired outcome: This is what I have implemented so far: <div class="bg"></div> .bg { position: r ...

What is the reasoning behind deploying both the source code and node_modules?

My framework of choice is CRA ([email protected]). When I serve my app locally using webpack devserver, I can see all the expected files deployed including bundle and chunks. However, when I serve my build folder after running npm run build followed ...

How can I preselect an item in a dropdown list in HTML using the result of an SQL query

Is this the correct method for setting a default value in an HTML drop down menu? The variable $vendor_name is determined by retrieving an array of results through a query, which is then looped to generate table rows in HTML. Consequently, the value of $v ...

The onsubmit event in Javascript activates the parent's onclick event

On my HTML page, I have a table with a form in each row. Clicking on the row should open a detail page, but clicking within the form should not trigger this action. Here is an example of what my row looks like: <tr onclick="window.parent.location.href ...