【问题标题】:Re-render issue when trying to make a sortable collection of notes with react, tinymce and react-sortable-hoc尝试使用 react、tinymce 和 react-sortable-hoc 制作可排序的笔记集合时重新渲染问题
【发布时间】:2022-11-16 01:14:47
【问题描述】:

我正在开发一种工具,用于在工作现场做一些笔记以生成 pdf 报告。

在这个阶段,一切正常(添加、编辑、删除笔记)但是当我重新排序笔记集合时(拖动手柄是灰色按钮) ,React 重新渲染集合的所有 TinyMCE 编辑器,而它应该只更新注释位置。 TinyMCE 编辑器的内容没有改变,只是更新了位置。参见上面的 onSortEnd() 函数。

此操作耗时过长。此外,如果我在页面底部,则重新初始化所有 TinyMCE 编辑器,使页面回到顶部。

所以我的问题是:

有没有办法在不重新初始化所有编辑器的情况下更新编辑器的位置?

找到附上我的界面的屏幕。

我是法国人,对不起我的英语不好。

这里摘录重要代码:

RapportChantier.jsx

export function AddEdit() {

  const [rapport, setRapport] = useState({ id: null });
  const [notes, setNotes] = useState([]);
  

  const addNote = () => {
    notes.push({
      uuid: uuidv4(),
      id: null,
      content: "Ecrivez votre note ici ...",
      position: 0,
      rapport: "/api/rapport_chantiers/" + rapport.id,
    });
    setNotes(notes);
  };

  const removeNote = (id) => {
    const filteredNotes = notes.filter((note) => {
      if (note.id !== null) {
        return note.id !== id;
      } else {
        return note.uuid !== id;
      }
    });
    setNotes(filteredNotes);
  };

  const pushNote = (pushedNote) => {
    const pushedNoteIndex = notes.findIndex(
      (note) => note.uuid === pushedNote.uuid
    );
    notes[pushedNoteIndex] = pushedNote;
    setNotes(notes);
  };

  const onSortEnd = ({ oldIndex, newIndex }) => {
    const reorderedNotes = arrayMove(notes, oldIndex, newIndex);
    setNotes(reorderedNotes);
  };

  const SortableNotes = SortableContainer((props) => {
    return (
      <div className={props.className}>
        {notes.map((note, index) => (
          <SortableNote
            key={note.id}
            note={note}
            pushNote={pushNote}
            removeNote={removeNote}
            index={index}
          />
        ))}
      </div>
    );
  });

  return (
    <div className="bg-white" style={{ padding: "30px" }}>

      <SortableNotes
        className="mb-3"
        axis="y"
        onSortEnd={onSortEnd}
        useDragHandle={true}
        lockAxis={"y"}
      />

      <button onClick={addNote} className="btn btn-primary btn-sm">
        Ajouter une note
      </button>
    </div>
  );
}

笔记.jsx

export const SortableNote = SortableElement(Note);

export default function Note({ note: noteProps, removeNote, pushNote }) {
  const editorRef = useRef(null);

  const [note, setNote] = useState({ ...noteProps });
  const [content, setContent] = useState(noteProps.content);
  const [timeoutUpdate, setTimeoutUpdate] = useState(null);
  const [hasChanged, setHasChanged] = useState(0);

  const updateNote = async () => {
    if (!note.id) {
      const { status, response } = await sendJsonData(
        "/api/notes",
        { ...note, content },
        "post"
      );

      if (status === 201) {
        setNote(response);
      }
    } else {
      const { status, response } = await sendJsonData(
        "/api/notes/" + note.id,
        { ...note, content },
        "patch"
      );
      if (status === 200) {
        setNote(response);
      }
    }
  };

  useEffect(() => {
    if (hasChanged > 0) {
      clearTimeout(timeoutUpdate);
      setTimeoutUpdate(setTimeout(updateNote, 1000));
    }
  }, [hasChanged, content]);

  const DragHandle = SortableHandle(() => (
    <button
      className="btn btn-secondary btn-sm"
      onClick={(e) => e.preventDefault()}
    >
      <span className="icon fa-reorder"></span>
    </button>
  ));

  const handleChanges = (editorContent) => {
    setContent(editorContent);
    setHasChanged(hasChanged + 1);
  };

  return (
    note && (
      <div className="mt-3">
        <div className="row">
          <div className="col-11">
            <Editor
              tinymceScriptSrc={"/libs/tinymce/tinymce.min.js"}
              value={content ?? ""}
              onEditorChange={handleChanges}
              onInit={(evt, editor) => (editorRef.current = editor)}
              init={{
                height: 300,
                menubar: false,
                plugins: [],
                toolbar:
                  "undo redo | blocks | bold italic strikethrough underline forecolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat",

                content_style:
                  "body { font-family:Helvetica,Arial,sans-serif; font-size:14px }",
              }}
            />
          </div>

          <div className="col-1">
            <button className="btn btn-primary btn-sm">
              <span className="icon fa-plus"></span>
            </button>
            <DragHandle />
            <button
              className="btn btn-danger btn-sm"
              onClick={(e) => {
                e.preventDefault();
                removeNote(note.id ?? note.uuid);
              }}
            >
              <span className="icon fa-remove"></span>
            </button>
          </div>
        </div>
      </div>
    )
  );
}

【问题讨论】:

    标签: reactjs tinymce react-sortable-hoc


    【解决方案1】:

    我找到了解决问题的方法。

    问题是 react-sortable-hoc lib 不保留可排序项目的节点引用。

    因此,在拖放一个项目后,所有可排序的项目都会从集合中删除并重新创建。

    这一刻之间(当项目被删除并重新创建时),所有TinyMCE编辑器都重新初始化,如果页面内容的高度高于窗口高度,页面将自动回到顶部。

    我通过使用更新的包 @dnd-kit/sortable 解决了这个问题,它允许您获取可排序项目的节点引用并将其设置在 &lt;div&gt;&lt;whatever&gt; 中:

    您可以在此处查看使用示例:https://codesandbox.io/s/x9w71?file=/src/App.js

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-08-22
      • 1970-01-01
      • 2021-08-28
      • 2018-04-01
      • 2021-01-08
      • 2018-05-02
      • 2020-06-07
      • 2017-12-07
      相关资源
      最近更新 更多