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
属性的过渡。
它按预期工作。我只是不知道 为什么 它有效。
代码:
两个列表:
- 身高
shortList
需要70px
- 身高
longList
需要124px
const shortList = ["Item 1", "Item 2", "Item 3"];
const longList = ["Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6"];
我有一个名为 ListContainerDIV
的 styled-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。这些应用的确切顺序是一个实现细节,但它们是同步应用的,浏览器无法在两者之间进行绘制,所以最好同时应用。
我无法理解 React 更新 DOM 的确切时间。
注意:我在下面的例子中使用了styled-components
。
看这个例子:
代码沙箱:https://codesandbox.io/s/elegant-dirac-j6e54
表示容器max-height
属性的过渡。
它按预期工作。我只是不知道 为什么 它有效。
代码:
两个列表:
- 身高
shortList
需要70px
- 身高
longList
需要124px
const shortList = ["Item 1", "Item 2", "Item 3"];
const longList = ["Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6"];
我有一个名为 ListContainerDIV
的 styled-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。这些应用的确切顺序是一个实现细节,但它们是同步应用的,浏览器无法在两者之间进行绘制,所以最好同时应用。