Часто задаваемые вопросы по React Hooks: реализация getderivedstatefromprops приводит к рендерингу с некогерентным состоянием - PullRequest
1 голос
/ 08 марта 2019

ИМХО Предложение из FAQ по React Hooks # getDerivedStateFromProps приводит к одному первому рендерингу со значением row, которое не соответствует значению isScrollingDown.Поскольку вызов setIsScrollingDown только планирует новый рендеринг и не влияет на текущий рендеринг, последний будет выполняться с новым значением row и старым значением isScrollingDown.

Это поведениене эквивалентен статическому getderivedstatefromprops методу класса компонентов, который обеспечивает согласованность между row и isScrollingDown.

Не следует ли обновить пример чем-то вроде следующего кода, чтобы гарантировать согласованностьрендеринг?Или я что-то пропустил?

Спасибо!

function ScrollView({row}) {
    let [isScrollingDown, setIsScrollingDown] = useState(false);
    let [prevRow, setPrevRow] = useState(null);

    if (row !== prevRow) {
        // Row changed since last render. Update isScrollingDown.
        isScrollingDown = prevRow !== null && row > prevRow
        setIsScrollingDown(isScrollingDown);
        setPrevRow(row);
    }

    return `Scrolling down: ${isScrollingDown}`;
}

1 Ответ

0 голосов
/ 08 марта 2019

Вот важная часть документации, которая делает ваши изменения ненужными:

React повторно запустит компонент с обновленным состоянием сразу после выход из первого рендера, чтобы он не был дорогим.

Визуализация, где они не синхронизированы, никогда не будет передана в браузер. Фактически, если бы он возвращал дочерний компонент из рендеринга, рендеринг дочерних элементов не выполнялся до тех пор, пока состояние не будет обновлено (дочерние элементы, возвращенные из рендеринга, который обновил состояние, будут игнорироваться).

Ниже приведен пример с консольными журналами, добавленными, чтобы показать это. Обратите внимание, что при увеличении строки ScrollView визуализируется дважды, а ScrollingDown - только один раз, получая только последнюю версию состояния ScrollView.

import React, { useState } from "react";
import ReactDOM from "react-dom";

function ScrollingDown({ isScrollingDown, prevRow, row }) {
  console.log("ScrollingDown", isScrollingDown, prevRow, row);
  return (
    <div>
      {`Scrolling down: ${isScrollingDown}`}
      <br />
      {`prevRow: ${prevRow}`}
      <br />
      {`row: ${row}`}
    </div>
  );
}

function ScrollView({ row }) {
  let [isScrollingDown, setIsScrollingDown] = useState(false);
  let [prevRow, setPrevRow] = useState(null);

  if (row !== prevRow) {
    // Row changed since last render. Update isScrollingDown.
    setIsScrollingDown(prevRow !== null && row > prevRow);
    setPrevRow(row);
  }
  console.log("ScrollView", isScrollingDown, prevRow, row);
  return (
    <ScrollingDown
      isScrollingDown={isScrollingDown}
      prevRow={prevRow}
      row={row}
    />
  );
}

function App() {
  const [row, setRow] = useState(1);
  return (
    <div className="App">
      <ScrollView row={row} />
      <button onClick={() => setRow(prev => prev + 1)}>Increment Row</button>
    </div>
  );
}

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

Edit Hooks getDerivedStateFromProps

...