Реагировать на проблему useState со сложным объектом состояния в приложении Electron - PullRequest
0 голосов
/ 26 мая 2020

Я создаю приложение для текстового редактора с помощью 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, оператор журнала Text 2 показывает пустое состояние:

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

Если я загружу 2-й документ в редактор, при сохранении текста 2 будет отображаться содержимое 1-го документа. onSaveCurrentDocument всегда на шаг позади по состоянию.

В чем может быть проблема?

1 Ответ

1 голос
/ 26 мая 2020

В вашем 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

...