React 何时以及以什么顺序更新 DOM?

When and in what order does React update the DOM?

我无法理解 React 更新 DOM 的确切时间。

注意:我在下面的例子中使用了styled-components

看这个例子:

代码沙箱:https://codesandbox.io/s/elegant-dirac-j6e54

表示容器max-height属性的过渡。

它按预期工作。我只是不知道 为什么 它有效。

代码:

两个列表:

const shortList = ["Item 1", "Item 2", "Item 3"];
const longList = ["Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6"];

我有一个名为 ListContainerDIVstyled-component 容器,它将处理基于 props 的转换。道具名称是 idealHeight.

const ListContainerDIV = styled.div`
  overflow: hidden;
  max-height: ${props => props.idealHeight + "px"};
  transition: max-height ease-out .5s;
`;

应用组件

function App() {

  // STATE TO KEEP LIST AND REF FOR THE CONTAINER DIV ELEMENT
  const [list, setList] = useState(shortList);
  const containerDiv_Ref = useRef(null);

  // FUNCTION TO TOGGLE BETWEEN LISTS FROM BUTTON CLICK
  function changeList() {
    setList(prevState => {
      if (prevState.length === 3) {
        return longList;
      } else {
        return shortList;
      }
    });
  }

  // CALCULATING THE IDEALHEIGHT DURING THE RENDER
  let idealHeight = null;

  if (list.length === 3) {
    idealHeight = 70;
  } else if (list.length === 6) {
    idealHeight = 124;
  }

  // RETURNING THE LISTCONTAINER WITH THE `idealHeight` PROP
  return (
    <React.Fragment>
      <button onClick={changeList}>Change List</button>
      <ListContainerDIV ref={containerDiv_Ref} idealHeight={idealHeight}>
        <ListComponent list={list} />
      </ListContainerDIV>
    </React.Fragment>
  );
}

列表组件

这是渲染 <ul><li>'s

的简单组件
function ListComponent(props) {
  const listItems = props.list.map(item => <li key={item}>{item}</li>);
  return <ul>{listItems}</ul>;
}

问题

如果我在呈现列表之前就设置了组件的 max-height,这个转换如何工作?我的意思是,idealHeight 是在 App 渲染期间设置的。我在想 longList 会在已经有 max-height = 124 的容器中呈现?如果发生这种情况,我们就不会看到过渡,对吗?

在这种情况下,React 运行 的事件顺序是什么?

显然它在从 styled-component 容器更新 div 之前更新了 <ul><li>'s

内部组件的元素总是在外部组件的元素之前更新?


更新

刚找到 Dan Abramov 关于这个主题的推文:

https://twitter.com/dan_abramov/status/981869076166344704

传递给 useState 的参数,在本例中为 shortList,是初始状态。所以第一次渲染ListContainerDIV时,是基于list长度为3的,所以idealHeight = 70

关于计算虚拟dom,它首先渲染父组件,然后渲染子组件,然后是子组件,依此类推。所有这些都使用状态和道具的最新值,因此 App 和各种子组件都知道列表更长。这个虚拟 dom 只是 in-memory 对您希望页面外观的描述。

计算出虚拟 dom 后,React 会将之前的虚拟 dom 与新虚拟 dom 进行比较,并找出发生了什么变化。在这种情况下,它发现需要向 div 添加一个新样式,并且需要向 ul 插入一些新的 li。这些应用的确切顺序是一个实现细节,但它们是同步应用的,浏览器无法在两者之间进行绘制,所以最好同时应用。