用Electron应用程序中的复杂状态对象来反应useState问题

时间:2020-05-26 08:01:44

标签: javascript reactjs electron use-state

我正在使用React和Electron以及出色的Slate.js文本编辑器组件构建一个文本编辑器应用程序。我在管理自己的状态时遇到问题。

代码

这里是完整的主要应用组件:

import React, { useState, useMemo, useEffect } from 'react'
import { createEditor } from 'slate'
import { Slate, Editable, withReact } from 'slate-react'

import TopBar from './TopBar'

const { ipcRenderer } = require('electron')

export const createSlateValue = (text) => {
  const lines = text.split('\n')
  return lines.map(line => (
    {
      children: [{ text: line }]
    }
  ))
}

const getSlateValue = (editorValue) => editorValue.map(line => line.children[0].text).join('\n')

const Editor = () => {
  const [currentDocument, setCurrentDocument] = useState()
  const [isDoingFileOperations, setIsDoingFileOperations] = useState(false)
  const [editorValue, setEditorValue] = useState(createSlateValue(''))
  const editor = useMemo(() => withReact(createEditor()), [])

  const onLoadDocument = async (doc) => {
    setCurrentDocument(doc)
    // Load file from disk
    if (doc.path) {
      try {
        const text = await fsReadFileAsync(doc.path)
        setEditorValue(createSlateValue(text))
      } catch (error) {
        window.alert('An error ocurred reading the file :' + error.message)
      }
    } else {
      setEditorValue(createSlateValue(doc.name))
    }
  }

  const onSaveCurrentDocument = async () => {
    if (isDoingFileOperations) return
    setIsDoingFileOperations(true)
    try {
      if (!(currentDocument && currentDocument.path)) throw new Error('No file path is set')
      const text = getSlateValue(editorValue)
      // await fsWriteFileAsync(currentDocument.path, text)
      console.log('Text 2:', JSON.stringify(editorValue, null, 2))
    } catch (error) {
      window.alert('An error ocurred saving the file :' + error.message)
    } finally {
      setIsDoingFileOperations(false)
    }
  }

  const handleTextChange = (val) => {
    setEditorValue(val)
  }

  const requestDocument = doc => {
    ipcRenderer.send('request-document', doc)
  }

  useEffect(() => {
    const keyboardCommandListener = (event, cmd) => {
      if (cmd === 'save') onSaveCurrentDocument()
    }
    ipcRenderer.on('keyboard-command', keyboardCommandListener)

    const requestDocumentListener = (event, doc) => onLoadDocument(doc)
    ipcRenderer.on('request-document-results', requestDocumentListener)
    return () => {
      ipcRenderer.removeListener('keyboard-command', keyboardCommandListener)
      ipcRenderer.removeListener('request-document-results', requestDocumentListener)
    }
  }, [currentDocument])

  console.log('Text 1:', JSON.stringify(editorValue, null, 2))

  return (
    <div>
      <TopBar
        currentDocument={currentDocument}
        onLoadDocument={onLoadDocument}
        onSaveDocument={onSaveCurrentDocument}
      />
      <Slate
        editor={editor}
        value={editorValue}
        onChange={handleTextChange}
      >
        <Editable
          placeholder='Write here...'
          onKeyDown={handleKeyDown}
        />
      </Slate>
    </div>
  )
}
export default Editor

问题

当我将文本文档加载到编辑器中时,“文本1”日志正确显示,例如:

Text 1: [
  {
    "children": [
      {
        "text": "# Quadcopter with wheels"
      }
    ]
  },
  {
    "children": [
      {
        "text": ""
      }
    ]
  },
  {
    "children": [
      {
        "text": ""
      }
    ]
  }
]

但是当我使用onSaveCurrentDocument函数进行保存时,文本2日志语句显示为空状态:

Text 2: [
  {
    "children": [
      {
        "text": ""
      }
    ]
  }
]

如果我将第二个文档加载到编辑器中,则在保存文本2时将显示第一个文档的内容。 onSaveCurrentDocument在状态方面总是落后一步。

可能是什么问题?

1 个答案:

答案 0 :(得分:1)

您的useEffect缺少一些依赖项:

  useEffect(() => {
    const keyboardCommandListener = (event, cmd) => {
      if (cmd === 'save') onSaveCurrentDocument()
    }
    ipcRenderer.on('keyboard-command', keyboardCommandListener)

    const requestDocumentListener = (event, doc) => onLoadDocument(doc)
    ipcRenderer.on('request-document-results', requestDocumentListener)
    return () => {
      ipcRenderer.removeListener('keyboard-command', keyboardCommandListener)
      ipcRenderer.removeListener('request-document-results', requestDocumentListener)
    }
  }, [currentDocument, onSaveCurrentDocument, onLoadDocument])
// onSaveCurrentDocument, onLoadDocument were missing

您能否尝试围绕此挂钩建立登录名?我建议您使用eslint钩子检查