Реагировать на асинхронный обработчик события, эквивалентный обратному вызову useEffect отмены - PullRequest
0 голосов
/ 24 марта 2020

Если мой обработчик событий запускает асинхронный процесс, как я могу узнать, чтобы отменить этот процесс или проигнорировать его результат, если компонент перерисован? Как и шаблон отмены в Дане Абрамове. Полное руководство по использованию эффекта статья.

Я сделал минимальный пример: -

const {
  useState
} = React;

ReactDOM.render(<App/>, app);

function App() {
  const [ listitem, setListitem ] = useState("");
  const [ data, setData ] = useState(null);
  
  function buttonClick() {
    retrieve(listitem).then(
      newData => {
        // HOW DO I KNOW IF I SHOULD USE newData HERE???
        setData(newData);
      }
    );
  };
  
  function selectChange(e) {
    setListitem(e.target.value);
  };
  
  return <div>
    <select onClick={selectChange}>
      <option/>
      <option selected={"Spurs"===listitem}>Spurs</option>
      <option selected={"ManU"===listitem}>ManU</option>
      <option selected={"Chelsea"===listitem}>Chelsea</option>
      <option selected={"Albion"===listitem}>Albion</option>
    </select>
    <br/>
    <button onClick={buttonClick} disabled={listitem===""}>Get Data</button>
    <br/>
    {listitem && data && <div>Data for {listitem} [{data.length}]:</div>}
    <ul>
    {data && data.map(function(x) { return <li>{x}</li> })}
    </ul>
  </div>
};

function retrieve(x) {
  return new Promise((resolve) =>
    setTimeout(resolve, x==="Spurs" ? 4000 : 2000, [
      "data1 for " + x, "data2 for " + x, "data3 for " + x
    ]));
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.11.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>

Я делаю эту информацию для «Шпор» вместо другой команды, выбрав «Шпоры», затем «Получить данные», затем быстро выберите другую команду и нажмите «Получить данные быстро». Данные для другой команды отображаются, а затем заменяются данными для шпор. Например, если я выберу ManU после того, как получу: -

Данные для ManU [3]:

  • data1 для Spurs
  • data2 для Spurs
  • data3 для Шпор

1 Ответ

0 голосов
/ 24 марта 2020

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

Я думал, что смогу использовать useEffect, как в статье Дана Абрамова, если бы у меня был флаг загрузки , Я получил его на работу, но, может быть, это не самый лучший способ?

const {
  useState,
  useEffect
} = React;

ReactDOM.render(<App/>, app);

function App() {
  const [ listitem, setListitem ] = useState("");
  const [ data, setData ] = useState(null);
  const [ loading, setLoading ] = useState("");
  
  function buttonClick() {
    setLoading(listitem);
  };

  useEffect(function() {
    if (!loading) return;
    let cancel = false;
    retrieve(loading).then(
      newData => {
        if (cancel) return;
        setData(newData);
      }
    );
    return function() {
      cancel = true;
    };
  }, [loading]);
  
  function selectChange(e) {
    setListitem(e.target.value);
  };
  
  return <div>
    <select onClick={selectChange}>
      <option/>
      <option selected={"Spurs"===listitem}>Spurs</option>
      <option selected={"ManU"===listitem}>ManU</option>
      <option selected={"Chelsea"===listitem}>Chelsea</option>
      <option selected={"Albion"===listitem}>Albion</option>
    </select>
    <br/>
    <button onClick={buttonClick} disabled={listitem===""}>Get Data</button>
    <br/>
    {listitem && data && <div>Data for {listitem} [{data.length}]:</div>}
    <ul>
    {data && data.map(function(x) { return <li>{x}</li> })}
    </ul>
  </div>
};

function retrieve(x) {
  return new Promise((resolve) =>
    setTimeout(resolve, x==="Spurs" ? 4000 : 2000, [
      "data1 for " + x, "data2 for " + x, "data3 for " + x
    ]));
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.11.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>
...