Дождитесь сбоя flag = true, флаг всегда будет false - PullRequest
1 голос
/ 07 октября 2019

Я пытаюсь создать пользовательский хук для сохранения данных на сервере. Прямо сейчас я подделываю серверный вызов с помощью простого setTimeout, который устанавливает флаг создания данных на true через 2 секунды.

У меня есть функция, которая продолжает проверять флаг, прежде чем он разрешает Обещание.

Однако флаг никогда не становится истинным. Вот codesandbox .

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

app.tsx

function App() {
  const { createOrganization } = useCreateOrganization();
  const handleCreateOrg = () => {
    createOrganization("New Org Name");
  };

  return (
    <div className="App">
      <button onClick={handleCreateOrg}>Start process</button>
    </div>
  );
}

useCreateOrganization.tsx

export const useCreateOrganization = (): {
  createOrganization: (organizationName: string) => Promise<any>;
} => {
  const [isOrganizationCreated, setIsOrganizationCreated] = useState(false);

  useEffect(() => {
    if (isOrganizationCreated) {
      setIsOrganizationCreated(true);
    }
  }, [isOrganizationCreated]);

  // Fakes org creation on a server.
  const mockCreateOrg = (orgName: string) => {
    setTimeout(() => {
      setIsOrganizationCreated(true);
    }, 1500);
  };

  function until(conditionFunction): Promise<any> {
    const poll = (resolve, reject) => {
      if (conditionFunction()) {
        console.log("done");
        resolve();
      } else {
        console.log("not done yet!");
        setTimeout(_ => poll(resolve, reject), 500);
      }
    };

    return new Promise(poll);
  }

  const createOrganization = async (organizationName: string): Promise<any> => {
    mockCreateOrg(organizationName);
    setIsOrganizationCreated(false);
    return await until(() => isOrganizationCreated);
  };

  return { createOrganization };
}

1 Ответ

1 голос
/ 07 октября 2019

isOrganizationCreated всегда будет содержать начальное значение false, поскольку переменной в области действия useCreateOrganization никогда не назначается новое значение, так что это скорее базовая вещь закрытия JavaScript (если вы хотитечтобы узнать больше, посмотрите на * 1 ниже)

Проблема также заключается в том, что вы хотите реализовать императивный опрос (until) в мире React. Вместо этого вы должны принять декларативную природу React, используя state и props для запуска нового цикла рендеринга. Таким образом, вместо опроса вы можете вызвать API mockCreateOrg, который, в свою очередь, устанавливает новое состояние. Это новое состояние запускает повторное рендеринг, который может привести к побочным эффектам - например, console.log("done").

Я не уверен, почему вы хотите использовать Hooks именно в вашем образце, поэтому вот базовый пример выборки стри состояния: когда 1) крючок находится в "idle", 2) создается организация ("pending"), 3) создание орги завершено ("created").

Codesandbox

import * as React from "react";
import { render } from "react-dom";
import { useEffect, useState } from "react";

export const useCreateOrganization = (): {
  createOrganization: (organizationName: string) => Promise<any>;
} => {
  const [state, setState] = useState<"idle" | "pending" | "created">("idle");

  useEffect(() => {
    let interval;
    if (state === "pending") {
      interval = setInterval(() => console.log("not done yet!"), 500);
    } else if (state === "created") {
      console.log("done");
      // ...do some other things here...
      setState("idle");
    }
    return () => interval && clearInterval(interval);
  }, [state]);

  // Fakes org creation on a server.
  const mockCreateOrg = (orgName: string) => {
    setTimeout(() => {
      setState("created");
    }, 1500);
  };

  const createOrganization = async (organizationName: string): Promise<any> => {
    mockCreateOrg(organizationName);
    setState("pending");
  };

  return { createOrganization };
};

function App() {
  const { createOrganization } = useCreateOrganization();
  const handleCreateOrg = () => {
    createOrganization("New Org Name");
  };

  return (
    <div className="App">
      <button onClick={handleCreateOrg}>Start process</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
render(<App />, rootElement);

Дополнительная информация: замыкания в React Hooks (* 1)

При вызове замыкания createOrganization будет использоваться переменная isOrganizationCreated, определенная ввнешняя область (useCreateOrganization тело функции), которая во время вызова имеет значение начального состояния false. isOrganizationCreated всегда будет иметь буквальное значение false в этой области, переназначение никогда не произойдет (с const также невозможно). Запустив изменение состояния с помощью setIsOrganizationCreated, React внутренне обновляет свою ячейку памяти компонента , и с новым циклом рендеринга снова вызывает useCreateOrganization - теперь с обновленным состоянием isOrganizationCreated. Хотя это не меняет область закрытия первого useCreateOrganization вызова.

Надеюсь, это поможет.

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