简体   繁体   English

在 React 中使用 Immer 按索引删除数组中的元素

[英]Deleting Elements in array by index using Immer in React

I'm building this component using React where I can Add Delete and edit lessons and sections using immer library.我正在使用 React 构建这个组件,我可以使用 immer 库添加删除和编辑课程和部分。 However, when I add a new section I cant seem to delete a specific Lesson in the section, it deletes the last lesson created.但是,当我添加一个新部分时,我似乎无法删除该部分中的特定课程,它会删除最后创建的课程。 And Deleting a specific section is not working as well.并且删除特定部分也不起作用。 Can anyone give me a hint to this problem?谁能给我一个提示这个问题?

These are the two deletion function that are giving me a hard time:这些是让我很难过的两个删除 function :

 remove = (sectionIndex, lessonIndex) => {
    const nextState = produce(this.state, (draftState) => {
      draftState.list[sectionIndex].lessons.splice(lessonIndex, 1);
    });
    this.setState(nextState);
    this.id++;
  };

  deletesection(sectionIndex, i) {
    const nextState = produce(this.state, (draftState) => {
      draftState.list[sectionIndex].section.splice(i, 1);
    });
    this.setState(nextState);
    this.id++;
  }

Here is the a link to the sandbox reproduction code: https://codesandbox.io/s/serene-forest-hpv7r?file=/src/TestClonereact.jsx这是沙盒复制代码的链接: https://codesandbox.io/s/serene-forest-hpv7r?file=/src/TestClonereact.jsx

remove actually seemed to be working for me, but I spotted some errors with deletesection : remove实际上似乎对我有用,但我发现deletesection有一些错误:

  • The function takes two arguments (both of which seem to be the section index), but you only call it with one. function 需要两个 arguments (这两个似乎都是节索引),但您只能用一个调用它。
  • It's not an arrow function, so it will have its own this and won't be able to access this.state .它不是箭头 function,所以它会有自己的this并且无法访问this.state
  • You are accessing a property .section which does not seem to exist.您正在访问一个似乎不存在的属性.section
  • Instead of splice you would want to remove the whole section object from the draftState.list array.您不想splice ,而是希望从draftState.list数组中删除整个 object 部分。
deletesection = (sectionIndex) => {
  const nextState = produce(this.state, (draftState) => {
    delete draftState.list[sectionIndex];
  });
  this.setState(nextState);
}

My personal preference would be use curried functions rather than passing the sectionIndex all the way down to the Lesson component.我个人的偏好是使用 curried 函数,而不是将sectionIndex一直传递给Lesson组件。 Also you can use produce inside a setState callback rather than accessing this.state directly.您也可以setState回调中使用produce ,而不是直接访问this.state But those are just suggestions.但这些只是建议。 Here's my tweaked version:这是我的调整版本:

import React from "react";
import "./styles.css";
import EdiText from "react-editext";
import produce from "immer";
import { v4 as uuid } from "uuid";

const Lesson = ({ lesson, onSave, remove }) => {
  const { id } = lesson;
  return (
    <div key={id} id={`sectionlesson-${id}`}>
      <div className="section-titles">
        <i className="material-icons" id="iconsectionlist" type="button">
          list
        </i>

        <EdiText
          type="text"
          value="Lesson Title"
          onSave={onSave}
          key={id}
          id={`lesson-${id}`}
        />

        <i className="material-icons" id="iconsectiondel" type="button">
          text_fields
        </i>
        <i className="material-icons" id="iconsectiondel" type="button">
          smart_display
        </i>
        <i
          className="material-icons"
          id="iconsectiondel"
          onClick={remove}
          type="button"
        >
          delete
        </i>
      </div>
      <div className="testh"></div>
    </div>
  );
};

const Section = ({ section, onSave, remove, addlesson, deletesection }) => {
  const { id } = section;
  return (
    <div key={id} id={`sds-${id}`}>
      <div className="course-structure-form" key={id} id={`csf1-${id}`}>
        <div className="section-heading">
          <i className="material-icons" id="iconsection">
            api
          </i>

          <EdiText type="text" value="Section Title" onSave={onSave} />
        </div>

        {section.lessons.map((lesson, lessonIndex) => (
          <Lesson
            key={lesson.id}
            lesson={lesson}
            remove={remove(lessonIndex)}
            onSave={onSave}
          />
        ))}

        <div className="addnewlesson" onClick={addlesson}>
          <i
            className="material-icons"
            id="iconsectionde"
            role="button"
            type="button"
          >
            add_circle
          </i>

          <span>Add New Lesson</span>
        </div>
        <button onClick={deletesection}>Delete Section</button>
      </div>
    </div>
  );
};

class TestClonereact extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      list: []
    };
  }

  onSave = (val) => {
    console.log("Edited Value -> ", val);
  };

  lesson({ id }) {}

  addsection = () => {
    this.setState(
      produce((draftState) => {
        draftState.list.push({ id: uuid(), lessons: [] });
      })
    );
  };

  addlesson = (sectionIndex) => () => {
    this.setState(
      produce((draftState) => {
        // needs to have a unique id
        draftState.list[sectionIndex].lessons.push({ id: uuid() });
      })
    );
  };

  remove = (sectionIndex) => (lessonIndex) => () => {
    this.setState(
      produce((draftState) => {
        draftState.list[sectionIndex].lessons.splice(lessonIndex, 1);
      })
    );
  };

  deletesection = (sectionIndex) => () => {
    this.setState(
      produce((draftState) => {
        delete draftState.list[sectionIndex];
      })
    );
  };

  render() {
    return (
      <div>
        {this.state.list.map((section, i) => (
          <Section
            key={section.id}
            section={section}
            remove={this.remove(i)}
            addlesson={this.addlesson(i)}
            onSave={this.onSave}
            deletesection={this.deletesection(i)}
          />
        ))}

        <div className="add-section-button-structure">
          <button className="tablink" onClick={this.addsection}>
            Add New Section
          </button>
          <button className="tablink">Clear</button>
          <button className="tablink">Preview</button>
          <button className="tablink">Submit</button>
        </div>
      </div>
    );
  }
}

export default TestClonereact;

Code Sandbox Link 代码沙盒链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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