Как читать данные реагирования контекста / состояния внутри непрерывного asyn c l oop без перезапуска цикла - PullRequest
1 голос
/ 29 февраля 2020

Node, React, Hooks, только на стороне клиента

Я хочу иметь непрерывный l oop для API с очередью задач и задержками между принудительными вызовами (для этого l oop) нет Независимо от того, из какого компонента поступают запросы на вызовы.

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

Вот упрощенный пример проблемы: asyn c l oop работает за пределами новых экземпляров компонента, и я попытался получить состояние тремя способами с помощью вывода l oop меньшим шрифтом и кнопкой, чтобы изменить состояние:

  1. заключено state (предоставляется из контекста)

  2. передано в качестве параметра ref st

  3. и даже refState из useRef ( состояние)

https://codesandbox.io/s/compassionate-einstein-qyq87?fontsize=14&hidenavigation=1

Вы можете нажать кнопку добавления задачи и заметить, что внутренняя до l oop длина задачи не обновляется, поскольку это запущено. Я также могу отправить изнутри, но без текущего состояния, я сбрасываю глобальное состояние. Я добавил точечную анимацию, чтобы вы могли видеть, что l oop жив.

Я нашел решение, которое кажется хакерским, поэтому я не хочу, чтобы оно было «исправлено», поэтому искал более разумное решение:

РЕШЕНИЕ МОЖЕТ: добавить клонированный useState, который копирует состояние в клон при каждом изменении состояния (с useEffect), использовать setClone внутри в форме обратного вызова, чтобы получить состояние из «предыдущего значения». Непосредственное использование клона НЕ дает последнее состояние.

  const { state, dispatch } = React.useContext(Store);
  const [clone, setClone] = React.useState(state);
  React.useEffect(() => setClone(state), [state]);

  // api loop
  const apiLoop = async () => {
    let haxState;
    setClone(val => {
      haxState = val; // copying value
      return val; // not changing anything
    });
----------
   await new Promise(r => setTimeout(r, 1000));
    // loop self
    apiLoop();
  };

  const [isLooping, setLooping] = React.useState(false);
  if (!isLooping) {
    apiLoop(); // start
    setLooping(true); // label started so don't restart
  }

https://codesandbox.io/s/late-leftpad-5x2ti?fontsize=14&hidenavigation=1&theme=dark

Я был очень счастлив найти что-то совместимое с реагированием, которое позволит мне прочитать задачи из (своего рода) глобального состояния, но я могу sh Я мог бы сделать это непосредственно с объектом состояния вместо того, чтобы задействовать дополнительные useEffect и совершенно новые useState просто для клонирования моего состояния. Я также не уверен, может ли мой редуктор или контекст сделать что-то похожее на форму setState (value => b), чтобы получить последнее значение, оно было разработано, чтобы изменять значение, а не захватывать его, поэтому я нервничаю.

Я не очень заинтересован в каких-либо решениях, где останавливается l oop. Клиент может выдвигать на него сотни задач, которые не могут перекрываться, повторяться или постоянно останавливаться. Предположим, что не может быть какой-либо обработки на стороне сервера, чисто на стороне клиента. (не показано событие при разгрузке, которое убивает l oop при необходимости)

Любые идеи или мое решение не случайно и нормально использовать?

Спасибо


Обновление:

Может быть, я обдумывал это. Я забыл, что могу один раз использовать объекты classi c js, связанные ссылками, размещать их вне компонента, чтобы они не инициализировались при повторном рендеринге, и использовать их для получения самой последней версии состояния

import React from "react";
import { Store } from "./state";
import "./styles.css";

// value placed outside component where it's not remade
const last = {};

export const App = () => {
  // global state
  const { state, dispatch } = React.useContext(Store);
  // update reference for last.state object without updating reference for last object
  // so last still points to same const above but last.state points to newest state
  last.state = state;

  let a = 0; // little counter

  // api loop
  const apiLoop = async () => {
    if (window.output)
      window.output.innerHTML = `
      apiLoop:\n
      last.state.tasks: ${last.state.tasks.length}\n
      ${".".repeat((a++ % 3) + 1)}
    `;

    // 1000ms api delay for rate limit
    await new Promise(r => setTimeout(r, 1000));
    // loop self
    apiLoop();
  };

  // initialize loop
  const [isLooping, setLooping] = React.useState(false);
  if (!isLooping) {
    apiLoop(); // start
    setLooping(true); // label started so don't restart
  }

https://codesandbox.io/s/heuristic-dijkstra-27p36?fontsize=14&hidenavigation=1&theme=dark

Наверное, я ответил на свой вопрос. Сожалею. Я оставлю это на всякий случай, если есть более элегантные решения. Это намного чище без лишних реагирующих крючков, так что пока подойдет. Код песочницы работает:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...