Рубрики
Без рубрики

Электронные приключения: эпизод 54: Управление Notebook State с использованием IMMER

Для большинства этой серии мы использовали SVELTE, что чрезвычайно гибко в управлении сложным состоянием. Ты… Tagged с JavaScript, React, Electron, Python.

Для большинства этой серии мы использовали SVELTE, что чрезвычайно гибко в управлении сложным состоянием. Вы можете изменить все, что вы хотите, куда бы вы ни захотите, и на большинстве вы просто должны пинговать компонент с Foo Чтобы дать это знать, что Foo изменился каким-то необычным способом. Обычно вам это даже не нужно.

Реагировать гораздо более строгим, и для того, что нам нужно, мы не можем оставить состояние в отдельных компонентах, нам нужно потянуть его до Приложение составная часть. Изготовление модификаций глубоко вложенного состояния – это много неприятного кода, к счастью, в действии реагированного мира есть решение – Иммер и его крючки версия Useimmer Отказ

Итак, сначала мы NPM Установить использование-Immer И тогда мы можем начать!

src/index.css

Мы будем добавлять несколько кнопок, поэтому нам нужно добавить лишь небольшую запись для кнопок. Вот весь файл:

body {
  background-color: #444;
  color: #fff;
  font-family: monospace;
}

.command {
  width: 80em;
  margin-bottom: 1em;
}

.command textarea {
  min-height: 5em;
  width: 100%;
  background-color: #666;
  color: #fff;
  font: inherit;
  border: none;
  padding: 4px;
  margin: 0;
}

.command .output {
  width: 100%;
  min-height: 5em;
  background-color: #666;
  padding: 4px;
}

button {
  background-color: #666;
  color: #fff;
}

src/command.js.

Этот компонент имеет обрабатывает кусок кода, связанный с ним выход и несколько связанных с ним кнопок.

Интересная вещь – updateengrengry код, который получает часть Useimmer -манежный проект и может сделать глубокие модификации к нему.

Мне было интересно, если этот компонент должен также управлять бежать , Делитэтис и Addnew – а с Useimmer. Это на самом деле совсем хорошо. Я закончил не делать этого, как Приложение Также нужно Беги все кнопка, и имея Беги в Приложение , Но Удалить и Добавить новый Управляется в Команда Компонент чувствовал себя странно.

import React from "react"

export default ({input, output, updateEntry, run, deleteThis, addNew}) => {
  let handleChange = e => {
    updateEntry(entry => entry.input = e.target.value)
  }

  let handleKey = (e) => {
    if (e.key === "Enter" && e.metaKey) {
      run()
    }
  }

  return (
    
{output}
) }

src/app.js.

Приложение Компонент довольно большой, так что давайте покроем его кусочком.

Шаблон достаточно простой. Самый неприятный способ в том, что мы делаем запустить = {run (индекс)} вместо более обычного run = {(event) => run (index, event)} Отказ Я думаю, что это яснее, как шаблон уже очень занят, а слишком много => Там делают это очень трудно прочитать.

import React from "react"
import { useImmer } from "use-immer"
import CommandBox from "./CommandBox.js"

export default (props) => {
  ...

  return (
    <>
      

Notebook App

{notebook.map(({input,output}, index) => ( ))}
) }

Но сначала нам нужно создать состояние. Я только что добавил несколько случайных фрагментов Python. Useimmer имеет очень похоже на API к Уместите :

  let [notebook, updateNotebook] = useImmer([
    { input: "print('Hello')", output: "" },
    { input: "print('World')", output: "" },
    { input: "print(f'2+2={2+2}')", output: "" },
  ])

Теперь вот весело один – updateentry. . Это каррическая функция, которую мы все в полной мере, делаем, делая UpdateEntry = {updateEntry (index)} в шаблоне.

CommandBox . Компонент изменяет только первый аргумент своего обратного вызова. Я также отправил это Проект и Индекс Потому что я думал Addnew и Делитэтис Буду удалось там, тогда я закончил не так, но я думаю, что все в порядке, чтобы оставить API немного более гибкой. Это похоже на то, как много обратных вызовов JavaScript пропускает дополнительные Индекс аргумент, который обычно игнорируется. Например .map (элемент => ...) на самом деле .map ((элемент, индекс, массив) => ...) .

  let updateEntry = (index) => (cb) => {
    updateNotebook(draft => {
      cb(draft[index], draft, index)
    })
  }

Все кнопки следуют за аналогичным карди -рисунком и имеют довольно простые обработчики:

  let run = (index) => async () => {
    let input = notebook[index].input
    let output = await window.api.runScript("python3", input)
    updateNotebook(draft => { draft[index].output = output })
  }

  let addNew = (index) => () => {
    updateNotebook(draft => {
      draft.splice(index + 1, 0, { input: "", output: "" })
    })
  }

  let deleteThis = (index) => () => {
    updateNotebook(draft => {
      draft.splice(index, 1)
      if (draft.length === 0) {
        draft.push({ input: "", output: "" })
      }
    })
  }

  let runAll = async () => {
    for (let index = 0; index < notebook.length; index++) {
      await run(index)()
    }
  }

Результат

Вот результаты:

Как обычно, Весь код для эпизода здесь Отказ

Ограничения

Мы сделали Frontend достаточно хорошо для простого ноутбука, но каждый код кода по-прежнему работает как нескрытый скрипт.

Также есть также немного состояния гонки, что если код занимает некоторое время, чтобы закончить, и пользователь удаляет или добавляет поля, когда код работает, вывод будет идти в неправильное место, но давайте не будем слишком беспокоиться об этом для этого Теперь.

Следующим шагом является использование простых HTTP Backend для запуска различных битов кода, которую мы отправляем в нее, в общем контексте.

Оригинал: “https://dev.to/taw/electron-adventures-episode-54-notebook-state-manegement-with-useimmer-b5l”