简体   繁体   English

React何时以何种顺序更新DOM?

[英]When and in what order does React update the DOM?

I'm having trouble undestanding the exact moment that React updates the DOM. 我遇到了React更新DOM的确切时刻。

Note: I'm using styled-components in the example below. 注意:我在下面的示例中使用styled-components

See this example: 看这个例子:

CodeSandbox: https://codesandbox.io/s/elegant-dirac-j6e54 CodeSandbox: https ://codesandbox.io/s/elegant-dirac-j6e54

It shows a transition of the max-height property of a container. 它显示了容器的max-height属性的转换。

在此输入图像描述

It workws as intended. 它按预期工作。 I just don't know WHY it works. 我只是不知道为什么它有效。

The code: 代码:

Two lists: 两个清单:

  • The shortList needs 70px of height shortList需要70px的高度
  • The longList needs 124px of height longList需要124px的高度
const shortList = ["Item 1", "Item 2", "Item 3"];
const longList = ["Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6"];

I have a styled-component container named ListContainerDIV that will handle the transition based on props . 我有一个名为ListContainerDIVstyled-component容器,它将处理基于props的转换。 The prop name is idealHeight . 道具名称是idealHeight

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

App Component 应用组件

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>
  );
}

List Component 列表组件

This is a simple component to render the <ul> and the <li>'s 这是渲染<ul><li>'s的简单组件

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

QUESTION

How can this transition be working if I'm setting the max-height of the component even before the list is rendered? 如果我在渲染列表之前设置组件的max-height ,那么这种转换如何工作呢? I mean, idealHeight is being set during the App render. 我的意思是,在App渲染期间正在设置idealHeight I was thinking that longList was going to be rendered in a container that already had max-height = 124 ? 我以为longList将在一个已经有max-height = 124的容器中呈现? And If that happened, we wouldn't be seeing a transition, right? 如果发生这种情况,我们就不会看到过渡,对吗?

What is the order of events that React is running in this situation? React在这种情况下运行的事件顺序是什么?

Apparently it updates the <ul> and the <li>'s before it updates the div from the styled-component container. 显然它在更新styled-component容器的div之前更新<ul><li>'s

An inner component's elements will always be update before the outer component's elements? 内部组件的元素将始终在外部组件的元素之前更新?


UPDATE UPDATE

Just found these tweets from Dan Abramov about this subject: 刚刚从Dan Abramov发现了关于这个主题的这些推文:

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

在此输入图像描述 在此输入图像描述

With regard to calculating the virtual dom, it starts by rendering the parent components, then renders the child components, then their children, and so on. 关于计算虚拟dom,它首先渲染父组件,然后渲染子组件,然后渲染子组件,依此类推。 All of this uses the latest values for state and props, so both App and the various child components know that the list is longer. 所有这些都使用状态和道具的最新值,因此App和各种子组件都知道列表更长。 This virtual dom is just an in-memory description of what you'd like the page to look like. 这个虚拟dom只是一个内存中描述你想要的页面的样子。

Once the virtual dom has been calculated, react compares the previous virtual dom with the new one, and finds what has changed. 一旦计算出虚拟dom,react会将之前的虚拟dom与新的dom进行比较,并找到已更改的内容。 In this case, it finds that there's a new style that needs to be added to the div, and some new li's that need to be inserted to the ul. 在这种情况下,它发现需要将一个新样式添加到div中,并且需要将一些新的li插入到ul中。 The exact order these are applied are an implementation detail, but they're applied synchronously and the browser cannot paint in between, so it might as well be simultaneously. 这些应用的确切顺序是一个实现细节,但它们是同步应用的,浏览器不能在两者之间绘制,因此它可能同时进行。

The argument passed to useState, shortList in this case, is the initial state. 传递给useState的参数,在这种情况下为shortList,是初始状态。 So when ListContainerDIV is rendered the first time, it's based on the list length being 3, so idealHeight = 70 所以当ListContainerDIV第一次渲染时,它基于列表长度为3,所以idealHeight = 70

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM