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

Javascript 在React中使用Immer按索引删除数组中的元素,javascript,reactjs,immer.js,Javascript,Reactjs,Immer.js,我正在使用React构建这个组件,在这里我可以使用immer库添加、删除和编辑课程和章节。但是,当我添加一个新部分时,我似乎无法删除该部分中的特定课程,它会删除创建的最后一个课程。 删除特定的部分也不起作用。有人能给我一个关于这个问题的提示吗 这两个删除功能让我很为难: remove = (sectionIndex, lessonIndex) => { const nextState = produce(this.state, (draftState) => {

我正在使用React构建这个组件,在这里我可以使用immer库添加、删除和编辑课程和章节。但是,当我添加一个新部分时,我似乎无法删除该部分中的特定课程,它会删除创建的最后一个课程。 删除特定的部分也不起作用。有人能给我一个关于这个问题的提示吗

这两个删除功能让我很为难:

 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++;
  }


这里是沙盒复制代码的链接:

删除实际上似乎对我有效,但我发现了
删除部分的一些错误:

  • 该函数接受两个参数(两个参数似乎都是节索引),但您只能用一个参数调用它
  • 它不是箭头函数,因此它将有自己的
    this
    ,并且将无法访问
    this.state
  • 您正在访问一个似乎不存在的属性
    .section
  • 您希望从
    draftState.list
    数组中删除整个截面对象,而不是
    splice
我个人的偏好是使用curried函数,而不是将
sectionIndex
一直传递到
Lesson
组件。您也可以使用
product
而不是直接访问
this.state
。但这些只是建议。以下是我经过调整的版本:

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;
从“React”导入React;
导入“/styles.css”;
从“反应编辑文本”导入编辑文本;
从“伊默”进口农产品;
从“uuid”导入{v4 as uuid};
const-Lesson=({Lesson,onSave,remove})=>{
const{id}=lesson;
返回(
列表
文本字段
智能显示
删除
);
};
const Section=({Section,onSave,remove,addlessource,deletesection})=>{
const{id}=节;
返回(
应用程序编程接口
{section.lessons.map((lesson,lessonIndex)=>(
))}
加上一个圆圈
添加新课程
删除节
);
};
类TestClonereact扩展了React.Component{
建造师(道具){
超级(道具);
此.state={
名单:[]
};
}
onSave=(val)=>{
console.log(“编辑值->”,val);
};
课程({id}){}
addsection=()=>{
这是我的国家(
生产((绘图状态)=>{
push({id:uuid(),课程:[]});
})
);
};
addlesson=(sectionIndex)=>()=>{
这是我的国家(
生产((绘图状态)=>{
//需要有一个唯一的id
draftState.list[sectionIndex].lessons.push({id:uuid()});
})
);
};
删除=(节索引)=>(lessonIndex)=>()=>{
这是我的国家(
生产((绘图状态)=>{
draftState.list[sectionIndex].lessons.splice(lessonIndex,1);
})
);
};
deletesection=(sectionIndex)=>()=>{
这是我的国家(
生产((绘图状态)=>{
删除draftState.list[节索引];
})
);
};
render(){
返回(
{this.state.list.map((节,i)=>(
))}
添加新节
清楚的
预览
提交
);
}
}
导出默认TestClonereact;

deletesection的第二个参数是什么?你怎么称呼它?@quirimo“i”是节索引,我通过返回节中的映射来称呼它,但我无法单独删除每个节,我想到的最好的办法是在一次单击中删除所有部分。我可能错了,但在上面的代码片段中,我没有看到fn被调用anywhere@quirimmo你说fn是什么意思?fn是功能的捷径谢谢,这正是我想做的,更感谢你在我做错的事情中为我打破了它。
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;