关于useState赋值后,导致页面重新渲染,数据初始化的问题

来源:8-5 在 App 中集成文件操作

张彬

2022-03-29

老师您好,我这发现,只要一更新编辑器里的内容,就会触发重新渲染,这个问题一直纠结中,因为一重新渲染,files就初始化了,以下是我的代码,麻烦老师给我看看
说明:我的相关组件版本:
“electron”: “^17.1.2”,
“react-simplemde-editor”: “^5.0.2”,


import React, { useState,useCallback,useMemo } from "react";
import { v4 as uuidv4 } from 'uuid';
import {flattenArr,objToArr} from '@/utils/helper'
import fileHelper from '@/utils/fileHelper'
import SimpleMDE from "react-simplemde-editor";
import 'bootstrap/dist/css/bootstrap.min.css'
import "easymde/dist/easymde.min.css";
import './App.scss';

import FileSearch from './components/FileSearch';
import FileList from './components/FileList';
import BottomBtn from '@/components/BottomBtn';
import TabList from '@/components/TabList';
import { faPlus,faFileImport,faSave } from '@fortawesome/free-solid-svg-icons'
import defaultFiles from './mock/defaultFiles';
const fs = window.require('fs')
const {join} = window.require('path')
const remote = window.require('@electron/remote')
function App() {
  const [files,setFiles] = useState(flattenArr(defaultFiles))
  const [activeFileID,setActiveFileID]=useState('')
  const [openedFileIDs,setOpenedFileIDs]=useState([])
  const [unsavedFileIDs,setUnsavedFileIDs]=useState([])
  const [searchedFiles,setSearchedFiles]=useState([])
  const filesArr=objToArr(files);
  const activeFile = files[activeFileID]
  const fileListArr =(searchedFiles.length>0)?searchedFiles:filesArr;
  
  const savedLocation=remote.app.getPath('documents')
  const openedFiles = openedFileIDs.map(openID=>{
    return files[openID]
  })
  
  //SimpleMDE config
  const autofocusNoSpellcheckerOptions = useMemo(() => {
    return {
      autofocus: true,
      spellChecker: false,
      minHeight:'515px'
    };
  }, []);
  const fileClick=(fileID)=>{
    //if openedFiles don't have the current ID
    //set current active id;
    setActiveFileID(fileID)
    console.log(files)
    //add new fileID to openedFiles
    if(!openedFileIDs.includes(fileID)){
      setOpenedFileIDs([...openedFileIDs,fileID])
    }
  }
  const tabClick=(fileID)=>{
    //set current active id;
    setActiveFileID(fileID)
  }

  const tabClose=fileID=>{
    //remove current id from openedFileIDs
    let idx=openedFileIDs.indexOf(fileID)
    const tabsWithout=openedFileIDs.filter(id=>id!==fileID)
    setOpenedFileIDs(tabsWithout)
    //set the active to the first opened tab if still tabs left
    if(fileID===activeFileID){
      if(tabsWithout.length>0){
        setActiveFileID(tabsWithout[idx>0?idx-1:0])
      }else{
        setActiveFileID('')
      }
    }
  }
  const fileChange=useCallback((fileID,value)=>{
    // loop through file array to update
    console.log(fileID,files,files[fileID])
    const newFile={...files[fileID],body:value}
    setFiles({...files,[fileID]:newFile})
    // update unsaveIDs
    if(!unsavedFileIDs.includes(fileID)){
      setUnsavedFileIDs([...unsavedFileIDs,fileID])
    }
  },[])

  const deleteFile=(fileID)=>{
    //filter out the current file id 
    delete files[fileID]
    setFiles(files)
    //close the tab if opened
    tabClose(fileID)
  }

  const updateFileName=(fileID,title,isNew)=>{
    const modifiedFile={...files[fileID],title,isNew:false};
    console.log(modifiedFile)
    if(isNew){
      fileHelper.writeFile(join(savedLocation,`${title}.md`),modifiedFile.body).then(res=>{
        setFiles({...files,[fileID]:modifiedFile})
      })
    }else{
      fileHelper.renameFile(join(savedLocation,`${files[fileID].title}.md`),join(savedLocation,`${title}.md`)).then(res=>{
        setFiles({...files,[fileID]:modifiedFile})
      })
    }
    console.log(files)
  }

  const fileSearch=(keyword)=>{
    //filter out this new files based on the keyword
    const newFiles=filesArr.filter(file=>file.title.includes(keyword));
    setSearchedFiles(newFiles)
  }
  const createNewFile=()=>{
    const isEditFile=filesArr.find(file=>file.isNew)
    if(!isEditFile){
      const newId=uuidv4();
      const newFiles={
        ...files,
        [newId]:{
          id:newId,
          title:'',
          body:'## 请输入 Markdown',
          createdAt:new Date().getTime(),
          isNew:true
        }
      }
      setFiles(newFiles)
    }
  }

  const saveCurrentFile=()=>{
    fileHelper.writeFile(join(savedLocation,`${activeFile.title}.md`),activeFile.body).then(res=>{
      setUnsavedFileIDs(unsavedFileIDs.filter(id=>id!==activeFile.id))
    })
  }
  
  return (
    <div className="App container-fluid  g-0">
      <div className='row g-0'>
        <div className='col-3 left-panel'>
          <FileSearch title="我的云文档" onFileSearch={fileSearch}></FileSearch>
          <FileList files={fileListArr} onFileClick={fileClick} onSaveEdit={updateFileName} onFileDelete={deleteFile}></FileList>
          <div className='row g-0 button-group'>
            <div className='col g-0'><BottomBtn text="新建" colorClass="btn-primary" icon={faPlus} onBtnClick={createNewFile}></BottomBtn></div>
            <div className='col g-0'><BottomBtn text="导入" colorClass="btn-success" icon={faFileImport} onBtnClick={()=>{}}></BottomBtn></div>
          </div>
        </div>
        <div className='col-9 right-panel'>
          {!activeFile && 
            <div className="start-page">选择或者创建新的 Markdown 文档  </div>
          }
          {activeFile && <>
            <TabList files={openedFiles} activeId={activeFileID} unsaveIds={unsavedFileIDs} onTabClick={tabClick} onCloseTab={tabClose}></TabList>
            <SimpleMDE key={activeFile&&activeFile.id} value={activeFile&&activeFile['body']} options={autofocusNoSpellcheckerOptions} onChange={(v)=>{fileChange(activeFile.id,v)}}></SimpleMDE>
            <div className='col g-0'><BottomBtn text="保存" colorClass="btn-success" icon={faSave} onBtnClick={saveCurrentFile}></BottomBtn></div>
          </>}
        </div>
      </div>
    </div>
  );
}

export default App;

写回答

1回答

张彬

提问者

2022-03-29

老师您好,是下面这段代码的问题

const fileChange=useCallback((fileID,value)=>{    // loop through file array to update    console.log(fileID,files,files[fileID])    const newFile={...files[fileID],body:value}    setFiles({...files,[fileID]:newFile})    // update unsaveIDs    if(!unsavedFileIDs.includes(fileID)){      setUnsavedFileIDs([...unsavedFileIDs,fileID])    }  },[]) 但之前改这段代码,也是为了解决输入会引起重新渲染,拿不到activeID,但神奇的是,现在把这个代码改回去,又好了,实在有点想不通

0
0

2024更新 Electron+React+七牛云实战跨平台桌面应用

开发一款自动云同步的 Markdown 文件管理软件

1253 学习 · 463 问题

查看课程